我如何在Python中创建类(即static)变量或方法?
你也可以使用元类强制一个类为静态的。
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。
__new__
方法... - Ned Batchelder有关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
在静态意义上不与特定的实例相关联,但该值仍取决于(类的)实例。
使用对象数据类型是可能的,但对于像bool
、int
、float
或str
等原始类型,其行为与其他面向对象编程语言不同。因为在继承类中不存在静态属性。如果继承类中不存在属性,则Python会开始查找其父类。如果在父类中找到了该属性,则返回其值。当您决定在继承类中更改值时,静态属性将在运行时创建。下次读取继承静态属性时,它的值将被返回,因为它已经定义了。对象(列表、字典)作为引用工作,因此安全使用它们作为静态属性并继承它们。当您更改其属性值时,对象地址不会更改。
整数数据类型示例:
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
是的,在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
@property
,它与使用描述符相同,但代码量要少得多。 - Rickclass 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"
总结了其他答案,并添加了一些内容,有很多方式可以在Python中声明静态方法或变量。
可以简单地在声明的方法(函数)上方放置一个装饰器,将其变成静态方法。例如:
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
这个方法可以接收一个函数类型的参数,并返回传递进来的函数的静态版本。例如:
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
@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
@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
在一个类中,如果一个方法/变量是在所有其他方法之外声明的,则自动将其声明为static。
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中的面向对象编程。
int(''.join(digits))
会引发错误,因为 digits 被传递为整数列表,而 join 不会自动进行转换。请注意,get_digits 也是一个 setter... 尽管 Calculator 程序几乎在语法上保持一致,但它是一组糟糕的编程结构。 - cardsclass 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
(私有静态变量)。
tryIt
类代表我们需要使用的常规类。
现在,我为一个标志(staticFlag
)创建了一个对象。这个标志将作为引用发送给所有常规对象。
所有这些对象都被添加到列表tryArr
中。
此脚本结果:
False
False
False
False
False
True
True
True
True
True
对于使用 Python 3.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
hasattr(SomeClass,'x')
为False
。我怀疑这根本不是任何人所说的静态变量。 - Ricksome_var
是不可变的和静态定义的,还是不是?外部 getter 访问与变量是否静态有什么关系?现在我有很多问题。希望在你有时间的时候能听到一些答案。 - jmunschsome_var
根本不是类成员。在 Python 中,所有的类成员都可以从类外部访问。 - Ricknonlocal
关键字可以“提升”变量的作用域。类定义体的作用域是独立于其所处的作用域的 - 当你说 nonlocal some_var
时,它只是创建了一个非局部(即:不在类定义作用域中)的名称引用到另一个命名对象。因此它不会附加到类定义中,因为它不在类体作用域内。 - Rick
static
” 实际上有几个含义(由于评论长度非常严格,以下是缩写的定义)。有来自 C 的文件作用域static
,表示“此变量或函数仅可在此文件中使用”。还有类作用域static
,表示“此方法或字段与类型相关,而不是任何类型的实例”(在 C++ 中很少用,但在 C#、Java 和 ObjC 中很常见,例如,我认为这就是 OP 所问的内容)。还有函数中的局部变量static
,表示“此变量的值在函数调用之间保持不变”。 - jrh