class - Python中的静态类变量

  显示原文与译文双语对照的内容
0 0

python 中有静态类变量或者方法? 执行这里操作需要什么语法?

时间: 原作者:

0 0

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


>>> class MyClass:
... i = 3
...
>>> MyClass.i
3 

就像 @ millerdev 指出的那样,这创建了一个 class-level"我"变量,但是这与任何 instance-level"我"变量不同,所以你可以


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

这与 C++ 和Java不同,但与 C# 不同,在这里,静态成员不能通过引用实例来访问。

参见 python 教程在类对象和类对象的主题。

@Steve 约翰逊已经回答了静态方法,也在 python 库引用中的"内置函数"下文档。


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

@beidy 建议 classmethod s/staticmethod,作为方法然后接收类类型作为第一个参数,但我仍然有点模糊staticmethod这种方法的优点。 如果你也是,那么它可能并不重要。

原作者:
0 0

@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__
{}

注意实例变量 t.i 走出同步"静态"类变量属性 i 时直接在 t 设置。 这是因为 i re-bound在 t 命名空间,这是有别于 Test 名称空间。 如果要更改"静态"变量的值,则必须在最初定义的作用域( 或者对象) 中更改它。 我把"静态"引号是因为 python 真的没有静态变量, C++ 和java。

虽然没有说任何特定的静态变量或方法,在 python 教程有一些相关信息类和类对象。

@Steve 约翰逊还回答了关于静态方法,也记录下"内置函数"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

0 0

是的。你可以有类方法使用 @classmethod 装饰。

另外,如果我正确解释你的问题,你可以在类名称之后声明静态字段,就像( 用示例):


class test:
 var=5 #static field

t = test() #example object 1
print t.var #should be 5
t2 = test() #example object 2
t.var = 2
print t.var #should be 2 now

原作者:
0 0

你也可以将类变量动态添加到类中


>>> 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]

原作者:
0 0

静态和类方法

就像其他答案所指出的,静态和类方法很容易使用内置的decorator实现:


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()的第一个参数是绑定到类对象本身 ( e.g,在本例中为 Test ) 。 对于 MyStaticMethod(),所有参数都是绑定的,并且根本没有参数。

"静态变量"

然而,实现"静态变量"( 可变静态变量,无论如何,如果这不是一个矛盾。)没有直接的。 就像 milldev 在他的回答中指出的,问题是 python 属性的类不是真正的"静态变量"。 请考虑:


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 已经添加了一个新的实例属性 ix,而不是改变 Testi 属性的值。

需要静态变量行为 换句话说,在多个实例之间同步属性,可以通过将类属性转换为属性来实现:


class Test(object):
 _i = 3
 @property
 def i(self)
 return self._i
 @i.setter
 def i(self,val):
 self._i = val

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

class Test(object):
 _i = 3
 def get_i(self)
 return self._i
 def set_i(self,val):
 self._i = val
 i = property(get_i, set_i)

现在你可以:


x1 = Test()
x2 = Test()
x1.i = 50
assert x2.i == x1.i # no error
assert x2.i == 50 # the property is synced

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

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

请注意,从技术上讲,i 根本不是一个变量;它是一个属性,这是一个特殊类型的描述符。 但是,属性行为现在等价于所有类实例中的( 可变的) 静态变量。

不可变的"静态变量"

对于真正的静态变量行为( 例如 。 不可变),只需忽略属性 setter:


class Test(object):
 _i = 3
 @property
 def i(self)
 return type(self)._i

## ALTERNATIVE IMPLEMENTATION - 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:


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

要注意的一点是

请注意,上面的方法只有使用实例的类——他们将不是当使用类本身工作。 下面举个例子:


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 产生一个错误,这意味着 iTestx 是两个不同的对象的属性。

很多人会发现这个惊人的惊喜。 但是,它不应该是。 如果返回并检查 Test 类定义( 第二个版本),我们会注意到这一行:


 i = property(get_i)

显然,成员 iTest 对象必须是一个属性,即从 property 函数返回类型的对象。

如果你仍然觉得困惑,你还不知道 python的基本部分是如何工作的。 你很可能仍然从其他语言的角度考虑它( 例如。 Java或者 C++ 。你应该研究返回 python 属性,描述符协议和方法解析顺序( MRO )的顺序。

下面我提出解决上述'gotcha';然而我建议——strenuously——你不要试图做一些类似以下至少直到你彻底明白为什么 assert Test.i = x.i 导致错误。

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

我在下面给出了( python 3 ) 解决方案仅供参考。 我不是把它当作"好解决方案"来批准。 我怀疑在 python 中模拟其他语言的静态变量行为是否真的需要。 然而,不管它是否真正有用,下面的内容有助于进一步理解 python 如何工作。

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

元类是类的类。 python ( 例如,"新样式"类 python 2.3我相信) 中所有类的默认元类是 type 。 例如:


type(int) # class 'type'
type(str) # class 'type'
class Test(): pass
type(Test) # class 'type'

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


class MyMeta(type): pass

并将它应用到你自己的类,如( 仅 python 3 ):


class MyClass(metaclass = MyMeta):
 pass
type(MyClass) # class MyMeta

下面是我创建的一个元类,它试图模仿其他语言的"静态变量"行为。 这相当复杂,但它基本上是通过替换普通的getter,setter和deleter来工作的,以检查所请求的属性是否是一个"静态变量"。 "静态变量"的目录存储在 StaticVarMeta.statics 属性中。 如果请求的属性不是"静态变量",该类将返回默认属性 get/set/delete 行为。 如果是"静态变量",它尝试使用替代解析顺序( 我把它叫做 __sro__,或者"静态解析顺序") 来解析属性请求。


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 = 1 # regular attribute

 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 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, 14, 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

原作者:
0 0

我个人会在需要静态方法时使用 classmethod 。 主要是因为我把这个类作为一个参数。


class myObj(object):
 def myMethod(cls)
. . .
 myMethod = classmethod(myMethod)

或者使用装饰器


class myObj(object):
 @classmethod
 def myMethod(cls)

对于静态属性。。请查阅一些 python 定义。 变量总是可以更改。有两种类型的变量:可变变量和可变变量。 此外,还有类属性和实例属性。 在 java & c+ +的意义上,什么都不像静态属性

为什么在 Pythonic 意义中使用静态方法,如果它与类无关 ! 如果我是你,我会使用classmethod或者定义独立于类的方法。

原作者:
0 0

你也可以使用元类将一个类强制为静态的。


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 。

0 0

关于静态属性的一个特别注意事项是&实例属性,如下面的示例所示:


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 中声明的每个属性类在内存中总是有一个静态槽

原作者:
0 0

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设置classmethod使用装饰 @classmethod 。

我们可以通过传入类的一个实例,在类中调用 myInstanceMethod,比如这样


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

0 0

在任何成员方法之外定义成员变量时,变量可以是静态的,也可以是non-static的,具体取决于变量是如何表示的。

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

...