Python中是否可以有静态类变量或方法?执行此操作需要什么语法?
25 回答
在类定义内但不在方法内声明的变量是类或静态变量:
>>> class MyClass:
... i = 3
...
>>> MyClass.i
3
正如@millerdev指出的那样,这会创建一个类级i
变量,但这与任何实例级i
变量不同,所以你可以
>>> m = MyClass()
>>> m.i = 4
>>> MyClass.i, m.i
>>> (3, 4)
这与 C++ 和 Java 不同,但与 C# 并没有太大不同,后者不能使用对实例的引用来访问静态成员。
@Steve Johnson 已经回答了有关静态方法的问题,也记录在Python 库参考中的“内置函数”下。
class C:
@staticmethod
def f(arg1, arg2, ...): ...
@beidy 建议使用classmethod而不是 staticmethod,因为该方法会接收类类型作为第一个参数。
@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
内重新绑定t
,这与Test
命名空间不同。如果要更改“静态”变量的值,则必须在最初定义的范围(或对象)内更改它。我将“静态”放在引号中,因为 Python 并没有 C++ 和 Java 那样的静态变量。
虽然它没有具体说明静态变量或方法,但Python 教程有一些关于类和类对象的相关信息。
@Steve Johnson 还回答了有关静态方法的问题,也记录在 Python 库参考中的“内置函数”下。
class Test(object):
@staticmethod
def f(arg1, arg2, ...):
...
@beid 还提到了 classmethod,它类似于 staticmethod。类方法的第一个参数是类对象。例子:
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 be the same as Test.i = arg1
静态和类方法
正如其他答案所指出的,静态和类方法可以使用内置装饰器轻松完成:
class Test(object):
# regular instance method:
def my_method(self):
pass
# class method:
@classmethod
def my_class_method(cls):
pass
# static method:
@staticmethod
def my_static_method():
pass
像往常一样,第一个参数my_method()
绑定到类实例对象。相反,第一个参数 to绑定到类对象本身my_class_method()
(例如,在这种情况下,)。对于,没有任何参数是绑定的,并且完全有参数是可选的。Test
my_static_method()
“静态变量”
但是,实现“静态变量”(无论如何,可变静态变量,如果这在术语上不矛盾的话......)并不那么简单。正如 millerdev在他的回答中指出的那样,问题在于 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
添加了一个新的实例属性i
,x
而不是更改Test
类i
属性的值。
部分预期的静态变量行为,即多个实例之间的属性同步(但不与类本身同步;参见下面的“gotcha”),可以通过将类属性转换为属性来实现:
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)
现在你可以这样做:
x1 = Test()
x2 = Test()
x1.i = 50
assert x2.i == x1.i # no error
assert x2.i == 50 # the property is synced
静态变量现在将在所有类实例之间保持同步。
(注意:也就是说,除非一个类实例决定定义它自己的版本_i
!但是如果有人决定这样做,他们应该得到他们得到的,不是吗???)
请注意,从技术上讲,i
它仍然根本不是“静态变量”;它是 a property
,它是一种特殊类型的描述符。但是,该property
行为现在等效于跨所有类实例同步的(可变)静态变量。
不可变的“静态变量”
对于不可变的静态变量行为,只需省略property
setter:
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
:
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
产生错误,因为 和 的属性i
是两个不同的对象。Test
x
许多人会对此感到惊讶。但是,它不应该。如果我们返回并检查我们的Test
类定义(第二个版本),我们会注意到这一行:
i = property(get_i)
显然,成员i
必须Test
是property
对象,也就是property
函数返回的对象类型。
如果您觉得上述内容令人困惑,那么您很可能还在从其他语言(例如 Java 或 c++)的角度来思考它。你应该去研究property
对象,了解 Python 属性的返回顺序、描述符协议和方法解析顺序 (MRO)。
我在下面提出了上述“问题”的解决方案;但是,我会强烈建议您不要尝试执行以下操作,直到(至少)彻底理解assert Test.i = x.i
导致错误的原因。
REAL,ACTUAL静态变量 -Test.i == x.i
我在下面提供(Python 3)解决方案仅供参考。我不认可它是一个“好的解决方案”。我怀疑在 Python 中模拟其他语言的静态变量行为是否真的有必要。但是,不管它是否真的有用,下面的内容应该有助于进一步理解 Python 的工作原理。
更新:这个尝试真的很糟糕;如果您坚持做这样的事情(提示:请不要;Python 是一种非常优雅的语言,并且没有必要将它硬塞到像另一种语言一样的行为中),请改用Ethan Furman 的答案中的代码。
使用元类模拟其他语言的静态变量行为
元类是类的类。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
属性中。最初尝试使用替代解析顺序来解析所有属性请求。我称其为“静态解决顺序”或“SRO”。这是通过在给定类(或其父类)的“静态变量”集中查找请求的属性来完成的。如果属性未出现在“SRO”中,则该类将回退到默认属性获取/设置/删除行为(即“MRO”)。
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
您还可以动态地将类变量添加到类中
>>> 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]
就个人而言,每当我需要静态方法时,我都会使用类方法。主要是因为我将课程作为论据。
class myObj(object):
def myMethod(cls)
...
myMethod = classmethod(myMethod)
或使用装饰器
class myObj(object):
@classmethod
def myMethod(cls)
对于静态属性..是时候查找一些python定义了..变量总是可以改变的。它们有可变和不可变两种类型。此外,还有类属性和实例属性。在 java 和 c++ 的意义上,没有什么像静态属性那样
如果它与类没有任何关系,为什么要在 Python 意义上使用静态方法!如果我是你,我要么使用 classmethod,要么定义独立于类的方法。
python 中的静态方法称为classmethod。看看下面的代码
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 ,如下所示:
>>> MyClass.myInstanceMethod(MyClass())
output from an instance method
关于静态属性和实例属性的一件特别需要注意的事情,如下例所示:
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 类中声明的每个属性在内存中总是有一个静态槽。
在任何成员方法之外定义一些成员变量时,该变量可以是静态的或非静态的,具体取决于变量的表达方式。
- 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
可以有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
您还可以使用元类强制类是静态的。
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。
关于 Python 的属性查找的一个非常有趣的点是它可以用来创建“虚拟变量”:
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
在不与特定实例关联的意义上是静态的,但该值仍然取决于实例的(类)。
@dataclass 定义提供了用于定义实例变量和初始化方法的类级别名称__init__()
。如果你想要类级别的变量,@dataclass
你应该使用typing.ClassVar
类型提示。类型的ClassVar
参数定义了类级变量的类型。
from typing import ClassVar
from dataclasses import dataclass
@dataclass
class Test:
i: ClassVar[int] = 10
x: int
y: int
def __repr__(self):
return f"Test({self.x=}, {self.y=}, {Test.i=})"
使用示例:
> test1 = Test(5, 6)
> test2 = Test(10, 11)
> test1
Test(self.x=5, self.y=6, Test.i=10)
> test2
Test(self.x=10, self.y=11, Test.i=10)
是的,绝对可以在 python 中编写静态变量和方法。
静态变量: 在类级别声明的变量称为静态变量,可以使用类名直接访问。
>>> class A:
...my_var = "shagun"
>>> print(A.my_var)
shagun
实例变量:类的实例相关和访问的变量是实例变量。
>>> a = A()
>>> a.my_var = "pruthi"
>>> print(A.my_var,a.my_var)
shagun pruthi
静态方法:与变量类似,静态方法可以直接使用类名访问。无需创建实例。
但请记住,静态方法不能在 python 中调用非静态方法。
>>> class A:
... @staticmethod
... def my_static_method():
... print("Yippey!!")
...
>>> A.my_static_method()
Yippey!!
关于这个答案,对于常量静态变量,您可以使用描述符。这是一个例子:
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
导致 ...
small demo 10
small subdemo 100
big demo 10
big subdemo 10
pass
如果悄悄地忽略设置值(上面)不是你的事,你总是可以引发异常。如果您正在寻找 C++、Java 风格的静态类变量:
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 本身没有明确的静态数据成员,但我们可以这样做
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())
输出
0
0
1
1
解释
here object (x) alone increment the counter variable
from 0 to 1 by not object y. But result it as "static counter"
使用 Object 数据类型是可能的。但是像 bool
,或bahaviour 这样int
的原始类型与其他 OOP 语言不同。因为在继承类中不存在静态属性。如果继承类中不存在属性,Python 开始在父类中查找它。如果在父类中找到,则返回其值。当您决定更改继承类中的值时,将在运行时创建静态属性。在下一次读取继承的静态属性时,它的值将被返回,因为它已经被定义了。对象(列表、字典)用作引用,因此将它们用作静态属性并继承它们是安全的。当您更改其属性值时,对象地址不会更改。float
str
整数数据类型的示例:
class A:
static = 1
class B(A):
pass
print(f"int {A.static}") # get 1 correctly
print(f"int {B.static}") # get 1 correctly
A.static = 5
print(f"int {A.static}") # get 5 correctly
print(f"int {B.static}") # get 5 correctly
B.static = 6
print(f"int {A.static}") # expected 6, but get 5 incorrectly
print(f"int {B.static}") # get 6 correctly
A.static = 7
print(f"int {A.static}") # get 7 correctly
print(f"int {B.static}") # get unchanged 6
基于refdatatypes库的解决方案:
from refdatatypes.refint import RefInt
class AAA:
static = RefInt(1)
class BBB(AAA):
pass
print(f"refint {AAA.static.value}") # get 1 correctly
print(f"refint {BBB.static.value}") # get 1 correctly
AAA.static.value = 5
print(f"refint {AAA.static.value}") # get 5 correctly
print(f"refint {BBB.static.value}") # get 5 correctly
BBB.static.value = 6
print(f"refint {AAA.static.value}") # get 6 correctly
print(f"refint {BBB.static.value}") # get 6 correctly
AAA.static.value = 7
print(f"refint {AAA.static.value}") # get 7 correctly
print(f"refint {BBB.static.value}") # get 7 correctly
为了避免任何潜在的混淆,我想对比静态变量和不可变对象。
一些原始对象类型,如整数、浮点数、字符串和 touples 在 Python 中是不可变的。这意味着由给定名称引用的对象如果属于上述对象类型之一,则不能更改。名称可以重新分配给不同的对象,但对象本身不能更改。
通过禁止变量名指向除当前指向的对象之外的任何对象,将变量设为静态更进一步。(注意:这是一个通用的软件概念,并非特定于 Python;有关在 Python 中实现静态的信息,请参阅其他人的帖子)。
我发现最好的方法是使用另一个类。您可以创建一个对象,然后在其他对象上使用它。
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
.
这个类应该呈现__success
静态变量(Private Static Var)。
tryIt
class 代表我们需要使用的常规类。
现在我为一个标志 ( staticFlag
) 制作了一个对象。该标志将作为对所有常规对象的引用发送。
所有这些对象都被添加到列表中tryArr
。
此脚本结果:
False
False
False
False
False
True
True
True
True
True
总结其他人的答案并补充,在python中声明静态方法或变量的方法有很多。
1.使用staticmethod()作为装饰器:
可以简单地将装饰器放在声明的方法(函数)之上,使其成为静态方法。例如。
class Calculator:
@staticmethod
def multiply(n1, n2, *args):
Res = 1
for num in args: Res *= num
return n1 * n2 * Res
print(Calculator.multiply(1, 2, 3, 4)) # 24
2.使用staticmethod()作为参数函数:
此方法可以接收函数类型的参数,并返回传递的函数的静态版本。例如。
class Calculator:
def add(n1, n2, *args):
return n1 + n2 + sum(args)
Calculator.add = staticmethod(Calculator.add)
print(Calculator.add(1, 2, 3, 4)) # 10
3.使用classmethod()作为装饰器:
@classmethod 对函数的影响与 @staticmethod 类似,但这次需要在函数中接受一个额外的参数(类似于实例变量的 self 参数)。例如。
class Calculator:
num = 0
def __init__(self, digits) -> None:
Calculator.num = int(''.join(digits))
@classmethod
def get_digits(cls, num):
digits = list(str(num))
calc = cls(digits)
return calc.num
print(Calculator.get_digits(314159)) # 314159
4.使用classmethod()作为参数函数:
@classmethod 也可以用作参数函数,以防万一不想修改类定义。例如。
class Calculator:
def divide(cls, n1, n2, *args):
Res = 1
for num in args: Res *= num
return n1 / n2 / Res
Calculator.divide = classmethod(Calculator.divide)
print(Calculator.divide(15, 3, 5)) # 1.0
5.直接申报
在所有其他方法之外但在类内部声明的方法/变量自动是静态的。
class Calculator:
def subtract(n1, n2, *args):
return n1 - n2 - sum(args)
print(Calculator.subtract(10, 2, 3, 4)) # 1
整个节目
class Calculator:
num = 0
def __init__(self, digits) -> None:
Calculator.num = int(''.join(digits))
@staticmethod
def multiply(n1, n2, *args):
Res = 1
for num in args: Res *= num
return n1 * n2 * Res
def add(n1, n2, *args):
return n1 + n2 + sum(args)
@classmethod
def get_digits(cls, num):
digits = list(str(num))
calc = cls(digits)
return calc.num
def divide(cls, n1, n2, *args):
Res = 1
for num in args: Res *= num
return n1 / n2 / Res
def subtract(n1, n2, *args):
return n1 - n2 - sum(args)
Calculator.add = staticmethod(Calculator.add)
Calculator.divide = classmethod(Calculator.divide)
print(Calculator.multiply(1, 2, 3, 4)) # 24
print(Calculator.add(1, 2, 3, 4)) # 10
print(Calculator.get_digits(314159)) # 314159
print(Calculator.divide(15, 3, 5)) # 1.0
print(Calculator.subtract(10, 2, 3, 4)) # 1
请参阅Python 文档以掌握 Python 中的 OOP。
类工厂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
所以这可能是一个 hack,但我一直在使用eval(str)
在 python 3 中获取一个静态对象,有点矛盾。
有一个 Records.py 文件,它只包含class
使用静态方法和保存一些参数的构造函数定义的对象。然后从另一个 .py 文件中,import Records
但我需要动态选择每个对象,然后根据读取的数据类型按需实例化它。
所以在哪里object_name = 'RecordOne'
或类名,我调用cur_type = eval(object_name)
然后实例化它你做cur_inst = cur_type(args)
但是在你实例化之前你可以调用静态方法cur_type.getName()
,例如,有点像抽象基类实现或任何目标。但是在后端,它可能在 python 中实例化并且不是真正的静态,因为 eval 正在返回一个对象......它必须已经实例化......它给出了类似静态的行为。
您可以使用列表或字典来获取实例之间的“静态行为”。
class Fud:
class_vars = {'origin_open':False}
def __init__(self, origin = True):
self.origin = origin
self.opened = True
if origin:
self.class_vars['origin_open'] = True
def make_another_fud(self):
''' Generating another Fud() from the origin instance '''
return Fud(False)
def close(self):
self.opened = False
if self.origin:
self.class_vars['origin_open'] = False
fud1 = Fud()
fud2 = fud1.make_another_fud()
print (f"is this the original fud: {fud2.origin}")
print (f"is the original fud open: {fud2.class_vars['origin_open']}")
# is this the original fud: False
# is the original fud open: True
fud1.close()
print (f"is the original fud open: {fud2.class_vars['origin_open']}")
# is the original fud open: False
例如,如果您尝试共享一个静态变量,以便在其他实例中增加它,则类似此脚本的内容可以正常工作:
# -*- coding: utf-8 -*-
class Worker:
id = 1
def __init__(self):
self.name = ''
self.document = ''
self.id = Worker.id
Worker.id += 1
def __str__(self):
return u"{}.- {} {}".format(self.id, self.name, self.document).encode('utf8')
class Workers:
def __init__(self):
self.list = []
def add(self, name, doc):
worker = Worker()
worker.name = name
worker.document = doc
self.list.append(worker)
if __name__ == "__main__":
workers = Workers()
for item in (('Fiona', '0009898'), ('Maria', '66328191'), ("Sandra", '2342184'), ('Elvira', '425872')):
workers.add(item[0], item[1])
for worker in workers.list:
print(worker)
print("next id: %i" % Worker.id)
这么说,当用户定义的类出现时创建静态变量,并定义一个静态变量,它应该遵循关键字self,
class Student:
the correct way of static declaration
i = 10
incorrect
self.i = 10
不像,@staticmethod
但类变量是类的静态方法,并与所有实例共享。
现在您可以像访问它一样
instance = MyClass()
print(instance.i)
或者
print(MyClass.i)
您必须将值分配给这些变量
我在尝试
class MyClass:
i: str
并在一个方法调用中分配值,在这种情况下它将不起作用并会引发错误
i is not attribute of MyClass