如何在Python中创建类(即静态)变量或方法?
当前回答
类变量并允许子类化
假设你不是在寻找一个真正的静态变量,而是一个类似于蟒蛇的东西,它可以为同意的成年人做同样的工作,那么就使用一个类变量。这将为您提供一个所有实例都可以访问(和更新)的变量
注意:其他许多使用类变量的答案都会破坏子类化。应避免直接按名称引用类。
from contextlib import contextmanager
class Sheldon(object):
foo = 73
def __init__(self, n):
self.n = n
def times(self):
cls = self.__class__
return cls.foo * self.n
#self.foo * self.n would give the same result here but is less readable
# it will also create a local variable which will make it easier to break your code
def updatefoo(self):
cls = self.__class__
cls.foo *= self.n
#self.foo *= self.n will not work here
# assignment will try to create a instance variable foo
@classmethod
@contextmanager
def reset_after_test(cls):
originalfoo = cls.foo
yield
cls.foo = originalfoo
#if you don't do this then running a full test suite will fail
#updates to foo in one test will be kept for later tests
将为您提供与使用Sheldon.foo处理变量相同的功能,并将通过以下测试:
def test_times():
with Sheldon.reset_after_test():
s = Sheldon(2)
assert s.times() == 146
def test_update():
with Sheldon.reset_after_test():
s = Sheldon(2)
s.updatefoo()
assert Sheldon.foo == 146
def test_two_instances():
with Sheldon.reset_after_test():
s = Sheldon(2)
s3 = Sheldon(3)
assert s.times() == 146
assert s3.times() == 219
s3.updatefoo()
assert s.times() == 438
它还允许其他人简单地:
class Douglas(Sheldon):
foo = 42
这也将起作用:
def test_subclassing():
with Sheldon.reset_after_test(), Douglas.reset_after_test():
s = Sheldon(2)
d = Douglas(2)
assert d.times() == 84
assert s.times() == 146
d.updatefoo()
assert d.times() == 168 #Douglas.Foo was updated
assert s.times() == 146 #Seldon.Foo is still 73
def test_subclassing_reset():
with Sheldon.reset_after_test(), Douglas.reset_after_test():
s = Sheldon(2)
d = Douglas(2)
assert d.times() == 84 #Douglas.foo was reset after the last test
assert s.times() == 146 #and so was Sheldon.foo
有关创建课程时要注意的事项的最佳建议,请查看Raymond Hettinger的视频https://www.youtube.com/watch?v=HTLu2DFOdTg
其他回答
总结其他人的回答并补充,在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中的OOP,请参阅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(私有静态变量)。
tryIt类表示我们需要使用的常规类。
现在我为一个标志(staticFlag)创建了一个对象。此标志将作为对所有常规对象的引用发送。
所有这些对象都被添加到列表tryArr中。
此脚本结果:
False
False
False
False
False
True
True
True
True
True
关于静态财产和实例财产,需要注意一件特殊的事情,如下例所示:
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类中声明的每个属性在内存中总是有一个静态槽。
就我个人而言,每当我需要静态方法时,我都会使用类方法。主要是因为我把课堂当作一个论点。
class myObj(object):
def myMethod(cls)
...
myMethod = classmethod(myMethod)
或使用装饰器
class myObj(object):
@classmethod
def myMethod(cls)
对于静态财产。。是时候查一下python的定义了。。变量始终可以更改。有两种类型是可变的和不可变的。。此外,还有类属性和实例属性。。没有什么东西真正像java&c意义上的静态属性++
为什么要使用Python意义上的静态方法,如果它与类没有任何关系!如果我是你,我要么使用classmethod,要么定义独立于类的方法。
关于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,因为尽管标签在不与特定实例关联的意义上是静态的,但值仍然取决于(的类)实例。