[python] 靜態類變量可能嗎?


Answers

@Blair Conrad表示在類定義中聲明的靜態變量,但不在方法內的是類或“靜態”變量:

>>> class Test(object):
...     i = 3
...
>>> Test.i
3

這裡有幾個難題。 從上面的例子開始:

>>> t = Test()
>>> t.i     # static variable accessed via instance
3
>>> t.i = 5 # but if we assign to the instance ...
>>> Test.i  # we have not changed the static variable
3
>>> t.i     # we have overwritten Test.i on t by creating a new attribute t.i
5
>>> Test.i = 6 # to change the static variable we do it by assigning to the class
>>> t.i
5
>>> Test.i
6
>>> u = Test()
>>> u.i
6           # changes to t do not affect new instances of Test

# Namespaces are one honking great idea -- let's do more of those!
>>> Test.__dict__
{'i': 6, ...}
>>> t.__dict__
{'i': 5}
>>> u.__dict__
{}

注意,當屬性i直接在t上設置時,實例變量ti與“static”類變量不同步。 這是因為it名稱空間內重新綁定,這與Test名稱空間不同。 如果要更改“靜態”變量的值,則必須在最初定義的範圍(或對象)內對其進行更改。 我將“static”放在引號中,因為在C ++和Java的意義上,Python並沒有真正的靜態變量。

儘管它沒有提及任何有關靜態變量或方法的具體內容,但Python教程還提供了有關類和類對象的一些相關信息。

@Steve Johnson也回答了有關靜態方法的問題,這些方法也記錄在Python庫參考中的“內置函數”下。

class Test(object):
    @staticmethod
    def f(arg1, arg2, ...):
        ...

@beid也提到了classmethod,這與staticmethod類似。 classmethod的第一個參數是類對象。 例:

class Test(object):
    i = 3 # class (or static) variable
    @classmethod
    def g(cls, arg):
        # here we can use 'cls' instead of the class name (Test)
        if arg > cls.i:
            cls.i = arg # would the the same as  Test.i = arg1

Question

是否有可能在Python中有靜態類變量或方法? 需要什麼語法才能做到這一點?




當在任何成員方法外定義一些成員變量時,變量可以是靜態的也可以是非靜態的,具體取決於變量的表達方式。

  • CLASSNAME.var是靜態變量
  • INSTANCENAME.var不是靜態變量。
  • 類內的self.var不是靜態變量。
  • 類成員函數中的var未定義。

例如:

#!/usr/bin/python

class A:
    var=1

    def printvar(self):
        print "self.var is %d" % self.var
        print "A.var is %d" % A.var


    a = A()
    a.var = 2
    a.printvar()

    A.var = 3
    a.printvar()

結果是

self.var is 2
A.var is 1
self.var is 2
A.var is 3



python中的靜態方法稱為classmethod s。 看看下面的代碼

class MyClass:

    def myInstanceMethod(self):
        print 'output from an instance method'

    @classmethod
    def myStaticMethod(cls):
        print 'output from a static method'

>>> MyClass.myInstanceMethod()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method myInstanceMethod() must be called [...]

>>> MyClass.myStaticMethod()
output from a static method

請注意,當我們調用方法myInstanceMethod時 ,會出現錯誤。 這是因為它要求在該類的一個實例上調用該方法。 方法myStaticMethod被設置為使用decorator @classmethod的類方法。

只是為了踢和咯咯,我們可以通過傳入類的實例來調用類的myInstanceMethod ,如下所示:

>>> MyClass.myInstanceMethod(MyClass())
output from an instance method



您也可以將類變量隨時添加到類中

>>> class X:
...     pass
... 
>>> X.bar = 0
>>> x = X()
>>> x.bar
0
>>> x.foo
Traceback (most recent call last):
  File "<interactive input>", line 1, in <module>
AttributeError: X instance has no attribute 'foo'
>>> X.foo = 1
>>> x.foo
1

而類實例可以改變類變量

class X:
  l = []
  def __init__(self):
    self.l.append(1)

print X().l
print X().l

>python test.py
[1]
[1, 1]



關於Python屬性查找的一個非常有趣的地方是它可以用來創建“ virtual變量”:

class A(object):

  label="Amazing"

  def __init__(self,d): 
      self.data=d

  def say(self): 
      print("%s %s!"%(self.label,self.data))

class B(A):
  label="Bold"  # overrides A.label

A(5).say()      # Amazing 5!
B(3).say()      # Bold 3!

通常在創建它們後沒有任何分配。 請注意,查找使用self因為儘管label在不與特定實例關聯的意義label是靜態的,但該值仍取決於實例的(類)。




我發現的最好方法是使用另一個班級。 您可以創建一個對象,然後在其他對像上使用它。

class staticFlag:
    def __init__(self):
        self.__success = False
    def isSuccess(self):
        return self.__success
    def succeed(self):
        self.__success = True

class tryIt:
    def __init__(self, staticFlag):
        self.isSuccess = staticFlag.isSuccess
        self.succeed = staticFlag.succeed

tryArr = []
flag = staticFlag()
for i in range(10):
    tryArr.append(tryIt(flag))
    if i == 5:
        tryArr[i].succeed()
    print tryArr[i].isSuccess()

通過上面的例子,我創建了一個名為staticFlag的類。

這個類應該呈現靜態var __success (私有靜態變量)。

tryIt類代表我們需要使用的常規課程。

現在我為一個標誌( staticFlag )創建了一個對象。 該標誌將作為所有常規對象的參考發送。

所有這些對像都被添加到tryArr列表中。

這個腳本結果:

False
False
False
False
False
True
True
True
True
True



有可能有static類變量,但可能不值得付出努力。

這是用Python 3編寫的一個概念驗證 - 如果任何確切的細節都是錯誤的,那麼可以調整代碼以便與static variable無關地匹配:

class Static:
    def __init__(self, value, doc=None):
        self.deleted = False
        self.value = value
        self.__doc__ = doc
    def __get__(self, inst, cls=None):
        if self.deleted:
            raise AttributeError('Attribute not set')
        return self.value
    def __set__(self, inst, value):
        self.deleted = False
        self.value = value
    def __delete__(self, inst):
        self.deleted = True

class StaticType(type):
    def __delattr__(cls, name):
        obj = cls.__dict__.get(name)
        if isinstance(obj, Static):
            obj.__delete__(name)
        else:
            super(StaticType, cls).__delattr__(name)
    def __getattribute__(cls, *args):
        obj = super(StaticType, cls).__getattribute__(*args)
        if isinstance(obj, Static):
            obj = obj.__get__(cls, cls.__class__)
        return obj
    def __setattr__(cls, name, val):
        # check if object already exists
        obj = cls.__dict__.get(name)
        if isinstance(obj, Static):
            obj.__set__(name, val)
        else:
            super(StaticType, cls).__setattr__(name, val)

並在使用中:

class MyStatic(metaclass=StaticType):
    """
    Testing static vars
    """
    a = Static(9)
    b = Static(12)
    c = 3

class YourStatic(MyStatic):
    d = Static('woo hoo')
    e = Static('doo wop')

和一些測試:

ms1 = MyStatic()
ms2 = MyStatic()
ms3 = MyStatic()
assert ms1.a == ms2.a == ms3.a == MyStatic.a
assert ms1.b == ms2.b == ms3.b == MyStatic.b
assert ms1.c == ms2.c == ms3.c == MyStatic.c
ms1.a = 77
assert ms1.a == ms2.a == ms3.a == MyStatic.a
ms2.b = 99
assert ms1.b == ms2.b == ms3.b == MyStatic.b
MyStatic.a = 101
assert ms1.a == ms2.a == ms3.a == MyStatic.a
MyStatic.b = 139
assert ms1.b == ms2.b == ms3.b == MyStatic.b
del MyStatic.b
for inst in (ms1, ms2, ms3):
    try:
        getattr(inst, 'b')
    except AttributeError:
        pass
    else:
        print('AttributeError not raised on %r' % attr)
ms1.c = 13
ms2.c = 17
ms3.c = 19
assert ms1.c == 13
assert ms2.c == 17
assert ms3.c == 19
MyStatic.c = 43
assert ms1.c == 13
assert ms2.c == 17
assert ms3.c == 19

ys1 = YourStatic()
ys2 = YourStatic()
ys3 = YourStatic()
MyStatic.b = 'burgler'
assert ys1.a == ys2.a == ys3.a == YourStatic.a == MyStatic.a
assert ys1.b == ys2.b == ys3.b == YourStatic.b == MyStatic.b
assert ys1.d == ys2.d == ys3.d == YourStatic.d
assert ys1.e == ys2.e == ys3.e == YourStatic.e
ys1.a = 'blah'
assert ys1.a == ys2.a == ys3.a == YourStatic.a == MyStatic.a
ys2.b = 'kelp'
assert ys1.b == ys2.b == ys3.b == YourStatic.b == MyStatic.b
ys1.d = 'fee'
assert ys1.d == ys2.d == ys3.d == YourStatic.d
ys2.e = 'fie'
assert ys1.e == ys2.e == ys3.e == YourStatic.e
MyStatic.a = 'aargh'
assert ys1.a == ys2.a == ys3.a == YourStatic.a == MyStatic.a



類工廠python3.6中的靜態變量

對於任何使用python3.6以上的類工廠的人來說,使用nonlocal關鍵字將其添加到正在創建的類的作用域/上下文中,如下所示:

>>> def SomeFactory(some_var=None):
...     class SomeClass(object):
...         nonlocal some_var
...         def print():
...             print(some_var)
...     return SomeClass
... 
>>> SomeFactory(some_var="hello world").print()
hello world





Related