python:静态类变量是可能的吗?

python中是否可能有静态类变量或方法?这需要什么语法?


在类定义中声明但不在方法中声明的变量是类或静态变量:

1
2
3
4
5
>>> class MyClass:
...     i = 3
...
>>> MyClass.i
3

正如@millerdev所指出的,这创建了一个类级别的i变量,但是这与任何实例级别的i变量都不同,所以您可以有

1
2
3
4
>>> m = MyClass()
>>> m.i = 4
>>> MyClass.i, m.i
>>> (3, 4)

这与c++和Java不同,但与c#没有太大区别,在c#中不能使用对实例的引用访问静态成员。

查看Python教程对类和类对象的主题有什么要说的。

@Steve Johnson已经回答了关于静态方法的问题,也在Python库参考的"内置函数"中进行了说明。

1
2
3
class C:
    @staticmethod
    def f(arg1, arg2, ...): ...

@beidy建议使用classmethods而不是staticmethod,因为该方法将类类型作为第一个参数,但是对于这种方法相对于staticmethod的优势,我仍然有些模糊。如果你也是,那也没什么关系。


@Blair Conrad说在类定义中声明的静态变量,而不是在方法中声明的静态变量是类或"静态"变量:

1
2
3
4
5
>>> class Test(object):
...     i = 3
...
>>> Test.i
3

这里有一些问题。从上面的例子继续:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
>>> 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__
{}

注意,当直接在t上设置属性i时,实例变量t.i如何与"静态"类变量不同步。这是因为it名称空间中被重新绑定,这与Test名称空间不同。如果想要更改"静态"变量的值,必须在最初定义它的范围(或对象)内更改它。我将"static"放在引号中,因为Python并不像c++和Java那样具有真正意义上的静态变量。

虽然Python教程没有说明关于静态变量或方法的任何具体内容,但是它提供了一些关于类和类对象的相关信息。

@Steve Johnson还回答了关于静态方法的问题,这些方法也记录在Python库参考中的"内置函数"中。

1
2
3
4
class Test(object):
    @staticmethod
    def f(arg1, arg2, ...):
        ...

@beid还提到了classmethod,它类似于staticmethod。类方法的第一个参数是类对象。例子:

1
2
3
4
5
6
7
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

Pictorial Representation Of Above Example


静态方法和类方法

正如其他答案所指出的,静态方法和类方法很容易实现使用内置装饰:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Test(object):

    # regular instance method:
    def MyMethod(self):
        pass

    # class method:
    @classmethod
    def MyClassMethod(klass):
        pass

    # static method:
    @staticmethod
    def MyStaticMethod():
        pass

与往常一样,MyMethod()的第一个参数绑定到类实例对象。相反,MyClassMethod()的第一个参数绑定到类对象本身(例如,在本例中,Test)。对于MyStaticMethod(),没有一个参数是绑定的,并且拥有参数是可选的。

"静态变量

然而,实现"静态变量"(嗯,可变静态变量,无论如何,如果这在术语上没有矛盾的话……)并不是那么简单。正如millerdev在他的回答中指出的,问题是Python的类属性并不是真正的"静态变量"。考虑:

1
2
3
4
5
6
7
8
class Test(object):
    i = 3  # This is a class attribute

x = Test()
x.i = 12   # Attempt to change the value of the class attribute using x instance
assert x.i == Test.i  # ERROR
assert Test.i == 3    # Test.i was not affected
assert x.i == 12      # x.i is a different object than Test.i

这是因为x.i = 12行向x添加了一个新的实例属性i,而不是更改Testi属性的值。

部分期望静态变量行为,即,在多个实例之间同步属性(但不与类本身同步;,可以通过将class属性转换为属性来实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Test(object):

    _i = 3

    @property
    def i(self):
        return type(self)._i

    @i.setter
    def i(self,val):
        type(self)._i = val

## ALTERNATIVE IMPLEMENTATION - FUNCTIONALLY EQUIVALENT TO ABOVE ##
## (except with separate methods for getting and setting i) ##

class Test(object):

    _i = 3

    def get_i(self):
        return type(self)._i

    def set_i(self,val):
        type(self)._i = val

    i = property(get_i, set_i)

现在你可以:

1
2
3
4
5
x1 = Test()
x2 = Test()
x1.i = 50
assert x2.i == x1.i  # no error
assert x2.i == 50    # the property is synced

静态变量现在将在所有类实例之间保持同步。

(注意:除非类实例决定定义自己版本的_i!)但如果有人决定这样做,他们就该得到他们应得的,不是吗??)

注意,从技术上讲,i根本不是一个"静态变量";它是一个property,这是一种特殊类型的描述符。然而,property行为现在等价于一个(可变的)静态变量,在所有类实例之间同步。

不可变"静态变量"

对于不可变静态变量行为,只需省略property setter:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Test(object):

    _i = 3

    @property
    def i(self):
        return type(self)._i

## ALTERNATIVE IMPLEMENTATION - FUNCTIONALLY EQUIVALENT TO ABOVE ##
## (except with separate methods for getting i) ##

class Test(object):

    _i = 3

    def get_i(self):
        return type(self)._i

    i = property(get_i)

现在尝试设置实例i属性将返回一个AttributeError:

1
2
3
x = Test()
assert x.i == 3  # success
x.i = 12         # ERROR

需要注意

注意,上面的方法只对类的实例起作用——当使用类本身时它们不起作用。举个例子:

1
2
3
4
5
6
x = Test()
assert x.i == Test.i  # ERROR

# x.i and Test.i are two different objects:
type(Test.i)  # class 'property'
type(x.i)     # class 'int'

assert Test.i == x.i产生一个错误,因为Testxi属性是两个不同的对象。

许多人会对此感到惊讶。然而,这不应该。如果我们回去检查我们的Test类定义(第二个版本),我们注意到这一行:

1
    i = property(get_i)

显然,Test的成员i必须是property对象,这是property函数返回的对象类型。

如果您发现上面的内容令人困惑,那么您很可能仍然是从其他语言(例如Java或c++)的角度来考虑它。您应该研究property对象,了解返回Python属性的顺序、描述符协议和方法解析顺序(MRO)。

我在下面提出了一个解决上述"问题"的方法;然而,我强烈建议,至少在完全理解assert Test.i = x.i为什么会导致错误之前,不要尝试做下面这样的事情。

实际的,实际的静态变量- Test.i == x.i

下面给出的(python3)解决方案仅供参考。我并不认为这是一个"好的解决方案"。我怀疑是否有必要在Python中模仿其他语言的静态变量行为。然而,不管它是否真的有用,下面的内容应该有助于进一步理解Python是如何工作的。

更新:这个尝试非常糟糕;如果你坚持做这样的事情(提示:请不要做;Python是一种非常优雅的语言,不需要硬把它硬塞进另一种语言中),而是使用Ethan Furman的答案中的代码。

使用元类模拟其他语言的静态变量行为

元类是类的类。Python中所有类的默认元类(即,我相信Python 2.3之后的"new style"类)是type。例如:

1
2
3
4
type(int)  # class 'type'
type(str)  # class 'type'
class Test(): pass
type(Test) # class 'type'

但是,您可以这样定义您自己的元类:

1
class MyMeta(type): pass

然后像这样应用到你自己的类中(只适用于python3):

1
2
3
4
class MyClass(metaclass = MyMeta):
    pass

type(MyClass)  # class MyMeta

下面是我创建的一个元类,它试图模拟其他语言的"静态变量"行为。它的工作原理是用版本替换默认的getter、setter和deleter,这些版本检查被请求的属性是否是"静态变量"。

"静态变量"的目录存储在StaticVarMeta.statics属性中。所有属性请求最初都尝试使用替代解析顺序进行解析。我将其称为"静态分辨率顺序",或"SRO"。这是通过在给定类(或其父类)的"静态变量"集中查找请求的属性来实现的。如果属性没有出现在"SRO"中,类将返回到默认属性get/set/delete行为(即"MRO")。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
from functools import wraps

class StaticVarsMeta(type):
    '''A metaclass for creating classes that emulate the"static variable" behavior
    of other languages. I do not advise actually using this for anything!!!

    Behavior is intended to be similar to classes that use __slots__. However,"normal"
    attributes and __statics___ can coexist (unlike with __slots__).

    Example usage:

        class MyBaseClass(metaclass = StaticVarsMeta):
            __statics__ = {'a','b','c'}
            i = 0  # regular attribute
            a = 1  # static var defined (optional)

        class MyParentClass(MyBaseClass):
            __statics__ = {'d','e','f'}
            j = 2              # regular attribute
            d, e, f = 3, 4, 5  # Static vars
            a, b, c = 6, 7, 8  # Static vars (inherited from MyBaseClass, defined/re-defined here)

        class MyChildClass(MyParentClass):
            __statics__ = {'a','b','c'}
            j = 2  # regular attribute (redefines j from MyParentClass)
            d, e, f = 9, 10, 11   # Static vars (inherited from MyParentClass, redefined here)
            a, b, c = 12, 13, 14  # Static vars (overriding previous definition in MyParentClass here)'''

    statics = {}
    def __new__(mcls, name, bases, namespace):
        # Get the class object
        cls = super().__new__(mcls, name, bases, namespace)
        # Establish the"statics resolution order"
        cls.__sro__ = tuple(c for c in cls.__mro__ if isinstance(c,mcls))

        # Replace class getter, setter, and deleter for instance attributes
        cls.__getattribute__ = StaticVarsMeta.__inst_getattribute__(cls, cls.__getattribute__)
        cls.__setattr__ = StaticVarsMeta.__inst_setattr__(cls, cls.__setattr__)
        cls.__delattr__ = StaticVarsMeta.__inst_delattr__(cls, cls.__delattr__)
        # Store the list of static variables for the class object
        # This list is permanent and cannot be changed, similar to __slots__
        try:
            mcls.statics[cls] = getattr(cls,'__statics__')
        except AttributeError:
            mcls.statics[cls] = namespace['__statics__'] = set() # No static vars provided
        # Check and make sure the statics var names are strings
        if any(not isinstance(static,str) for static in mcls.statics[cls]):
            typ = dict(zip((not isinstance(static,str) for static in mcls.statics[cls]), map(type,mcls.statics[cls])))[True].__name__
            raise TypeError('__statics__ items must be strings, not {0}'.format(typ))
        # Move any previously existing, not overridden statics to the static var parent class(es)
        if len(cls.__sro__) > 1:
            for attr,value in namespace.items():
                if attr not in StaticVarsMeta.statics[cls] and attr != ['__statics__']:
                    for c in cls.__sro__[1:]:
                        if attr in StaticVarsMeta.statics[c]:
                            setattr(c,attr,value)
                            delattr(cls,attr)
        return cls
    def __inst_getattribute__(self, orig_getattribute):
        '''Replaces the class __getattribute__'''
        @wraps(orig_getattribute)
        def wrapper(self, attr):
            if StaticVarsMeta.is_static(type(self),attr):
                return StaticVarsMeta.__getstatic__(type(self),attr)
            else:
                return orig_getattribute(self, attr)
        return wrapper
    def __inst_setattr__(self, orig_setattribute):
        '''Replaces the class __setattr__'''
        @wraps(orig_setattribute)
        def wrapper(self, attr, value):
            if StaticVarsMeta.is_static(type(self),attr):
                StaticVarsMeta.__setstatic__(type(self),attr, value)
            else:
                orig_setattribute(self, attr, value)
        return wrapper
    def __inst_delattr__(self, orig_delattribute):
        '''Replaces the class __delattr__'''
        @wraps(orig_delattribute)
        def wrapper(self, attr):
            if StaticVarsMeta.is_static(type(self),attr):
                StaticVarsMeta.__delstatic__(type(self),attr)
            else:
                orig_delattribute(self, attr)
        return wrapper
    def __getstatic__(cls,attr):
        '''Static variable getter'''
        for c in cls.__sro__:
            if attr in StaticVarsMeta.statics[c]:
                try:
                    return getattr(c,attr)
                except AttributeError:
                    pass
        raise AttributeError(cls.__name__ +" object has no attribute '{0}'".format(attr))
    def __setstatic__(cls,attr,value):
        '''Static variable setter'''
        for c in cls.__sro__:
            if attr in StaticVarsMeta.statics[c]:
                setattr(c,attr,value)
                break
    def __delstatic__(cls,attr):
        '''Static variable deleter'''
        for c in cls.__sro__:
            if attr in StaticVarsMeta.statics[c]:
                try:
                    delattr(c,attr)
                    break
                except AttributeError:
                    pass
        raise AttributeError(cls.__name__ +" object has no attribute '{0}'".format(attr))
    def __delattr__(cls,attr):
        '''Prevent __sro__ attribute from deletion'''
        if attr == '__sro__':
            raise AttributeError('readonly attribute')
        super().__delattr__(attr)
    def is_static(cls,attr):
        '''Returns True if an attribute is a static variable of any class in the __sro__'''
        if any(attr in StaticVarsMeta.statics[c] for c in cls.__sro__):
            return True
        return False


您还可以动态地向类添加类变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
>>> 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

类实例可以改变类变量

1
2
3
4
5
6
7
8
9
10
11
class X:
  l = []
  def __init__(self):
    self.l.append(1)

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

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


就我个人而言,每当我需要静态方法时,我都会使用classmethod。主要是因为我把这个类作为一个参数。

1
2
3
4
class myObj(object):
   def myMethod(cls)
     ...
   myMethod = classmethod(myMethod)

或者使用装饰器

1
2
3
class myObj(object):
   @classmethod
   def myMethod(cls)

静态属性. .现在是您查找一些python定义的时候了。变量总是可以改变的。它们有两种类型:可变的和不可变的。此外,还有类属性和实例属性。没有什么比java中的静态属性更好的了。c++

如果静态方法与类没有任何关系,为什么要使用python意义上的静态方法!如果我是你,我要么使用classmethod,要么定义独立于类的方法。


关于静态属性需要特别注意的一点是;实例属性,如下例所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class my_cls:
  my_prop = 0

#static property
print my_cls.my_prop  #--> 0

#assign value to static property
my_cls.my_prop = 1
print my_cls.my_prop  #--> 1

#access static property thru' instance
my_inst = my_cls()
print my_inst.my_prop #--> 1

#instance property is different from static property
#after being assigned a value
my_inst.my_prop = 2
print my_cls.my_prop  #--> 1
print my_inst.my_prop #--> 2

这意味着在将值分配给实例属性之前,如果我们试图通过实例访问该属性,将使用静态值。python类中声明的每个属性在内存中都有一个静态槽。


python中的静态方法称为类方法。看一下下面的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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使用装饰器@classmethod设置为一个类方法。

只是为了好玩和傻笑,我们可以在类上调用myInstanceMethod,方法是传入一个类的实例,就像这样:

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

当在任何成员方法之外定义某个成员变量时,该变量可以是静态的,也可以是非静态的,这取决于该变量是如何表示的。

类名。var是静态变量都。var不是静态变量。自我。类内的var不是静态变量。类成员函数中的var没有定义。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/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()

结果是

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

您还可以使用元类强制类成为静态的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class StaticClassError(Exception):
    pass


class StaticClass:
    __metaclass__ = abc.ABCMeta

    def __new__(cls, *args, **kw):
        raise StaticClassError("%s is a static class and cannot be initiated."
                                % cls)

class MyClass(StaticClass):
    a = 1
    b = 3

    @staticmethod
    def add(x, y):
        return x+y

然后,每当您试图初始化MyClass时,您会意外地得到一个StaticClassError。


可以使用static类变量,但可能不值得这样做。

这里有一个用Python 3编写的概念验证——如果有任何确切的细节是错误的,可以调整代码来匹配您所说的static variable:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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)

在使用:

1
2
3
4
5
6
7
8
9
10
11
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')

和一些测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
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

Python的属性查找非常有趣的一点是,它可以用来创建"虚拟变量":

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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在不与特定实例关联的意义上是静态的,但是值仍然依赖于实例的(类)。


绝对是的,Python本身并不显式地拥有任何静态数据成员,但是我们可以通过这样做来拥有

1
2
3
4
5
6
7
8
9
10
11
12
13
class A:
    counter =0
    def callme (self):
        A.counter +=1
    def getcount (self):
        return self.counter  
>>> x=A()
>>> y=A()
>>> print(x.getcount())
>>> print(y.getcount())
>>> x.callme()
>>> print(x.getcount())
>>> print(y.getcount())

输出

1
2
3
4
0
0
1
1

解释

1
2
here object (x) alone increment the counter variable
from 0 to 1 by not object y. But result it as"static counter"

对于这个答案,对于常量静态变量,可以使用描述符。这里有一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class ConstantAttribute(object):
    '''You can initialize my value but not change it.'''
    def __init__(self, value):
        self.value = value

    def __get__(self, obj, type=None):
        return self.value

    def __set__(self, obj, val):
        pass


class Demo(object):
    x = ConstantAttribute(10)


class SubDemo(Demo):
    x = 10


demo = Demo()
subdemo = SubDemo()
# should not change
demo.x = 100
# should change
subdemo.x = 100
print"small demo", demo.x
print"small subdemo", subdemo.x
print"big demo", Demo.x
print"big subdemo", SubDemo.x

导致……

1
2
3
4
small demo 10
small subdemo 100
big demo 10
big subdemo 10

如果您不喜欢悄悄地忽略设置值(pass),则始终可以引发异常。如果你正在寻找一个c++, Java风格的静态类变量:

1
2
3
4
5
6
7
8
9
class StaticAttribute(object):
    def __init__(self, value):
        self.value = value

    def __get__(self, obj, type=None):
        return self.value

    def __set__(self, obj, val):
        self.value = val

看看这个答案和官方文档如何获得更多关于描述符的信息。


为了避免任何潜在的混淆,我想对比静态变量和不可变对象。

一些基本对象类型,如整数、浮点数、字符串和元组,在Python中是不可变的。这意味着,如果对象属于上述对象类型之一,则由给定名称引用的对象不能更改。可以将名称重新分配给其他对象,但对象本身不能更改。

通过禁止变量名指向除它当前指向的对象之外的任何对象,使变量静态更进一步。(注意:这是一个通用的软件概念,不是特定于Python;有关用Python实现静态的信息,请参阅其他人的文章)。


我发现最好的方法是使用另一个类。您可以创建一个对象,然后在其他对象上使用它。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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(私有静态var)。

类表示我们需要使用的常规类。

现在我为一个标志创建了一个对象(staticFlag)。此标志将作为对所有常规对象的引用发送。

所有这些对象都被添加到列表tryArr中。

这个脚本的结果:

1
2
3
4
5
6
7
8
9
10
False
False
False
False
False
True
True
True
True
True

是的,用python编写静态变量和方法是完全可能的。

静态变量:类级声明的变量称为静态变量,可以使用类名直接访问。

1
2
3
4
5
    >>> class A:
        ...my_var ="shagun"

    >>> print(A.my_var)
        shagun

实例变量:由类的实例关联和访问的变量是实例变量。

1
2
3
4
   >>> a = A()
   >>> a.my_var ="pruthi"
   >>> print(A.my_var,a.my_var)
       shagun pruthi

静态方法:与变量类似,可以使用类名直接访问静态方法。不需要创建实例。

但是请记住,静态方法不能在python中调用非静态方法。

1
2
3
4
5
6
7
    >>> class A:
   ...     @staticmethod
   ...     def my_static_method():
   ...             print("Yippey!!")
   ...
   >>> A.my_static_method()
   Yippey!!


类工厂python3.6中的静态变量

对于任何使用python3.6及以上版本的类工厂的用户,请使用nonlocal关键字将其添加到正在创建的类的作用域/上下文中,如下所示:

1
2
3
4
5
6
7
8
9
>>> 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