我想在Python中创建一个管理所有静态成员的类。这些成员应该在课程定义期间初始化。由于以后需要重新初始化静态成员,我会将此代码放入类方法中。
我的问题:如何从班级内部调用这种类方法?
class Test():
# static member
x = None
# HERE I WOULD LOVE TO CALL SOMEHOW static_init!
# initialize static member in classmethod, so that it can be
#reinitialized later on again
@classmethod
def static_init(cls):
cls.x = 10
感谢任何帮助!
提前致谢, 沃尔克
答案 0 :(得分:19)
在您的示例中执行x=10
时,不仅该类不存在,而且该类方法也不存在。
Python中的执行自上而下。如果x=10
高于classmethod,则无法在此时访问classmethod,因为它尚未定义。
即使您可以运行classmethod,也没关系,因为该类还不存在,所以classmethod无法引用它。直到整个类块运行之后才会创建该类,所以当你在类块中时,没有类。
如果要分解某些类初始化,以便稍后可以按照描述的方式重新运行它,请使用类装饰器。类装饰器在创建类之后运行,因此它可以很好地调用classmethod。
>>> def deco(cls):
... cls.initStuff()
... return cls
>>> @deco
... class Foo(object):
... x = 10
...
... @classmethod
... def initStuff(cls):
... cls.x = 88
>>> Foo.x
88
>>> Foo.x = 10
>>> Foo.x
10
>>> Foo.initStuff() # reinitialize
>>> Foo.x
88
答案 1 :(得分:5)
通过同样附加类名来调用类方法:
class.method
在你的代码中,这样的东西就足够了:
Test.static_init()
你也可以这样做:
static_init(Test)
要在课堂内调用,请让您的代码执行此操作:
Test.static_init()
我的工作代码:
class Test(object):
@classmethod
def static_method(cls):
print("Hello")
def another_method(self):
Test.static_method()
和Test().another_method()
返回Hello
答案 2 :(得分:2)
您无法在classmethod
定义中调用class
,因为该类尚未完全定义,因此没有任何内容可以将该方法作为其第一个cls
参数传递。 ..经典的鸡蛋问题。但是,您可以通过重载元类中的__new__()
方法来解决此限制,并在创建类之后从那里调用classmethod,如下所示:
class Test(object):
# nested metaclass definition
class __metaclass__(type):
def __new__(mcl, classname, bases, classdict):
cls = type.__new__(mcl, classname, bases, classdict) # creates class
cls.static_init() # call the classmethod
return cls
x = None
@classmethod
def static_init(cls): # called by metaclass when class is defined
print("Hello")
cls.x = 10
print Test.x
输出:
Hello
10
答案 3 :(得分:1)
重新阅读小心这一问题后,我可以想到两个解决方案。第一个是应用Borg设计模式。第二个是丢弃类方法并使用模块级函数。这似乎可以解决您的问题:
def _test_static_init(value):
return value, value * 2
class Test:
x, y = _test_static_init(20)
if __name__ == "__main__":
print Test.x, Test.y
这是一个例子,我希望它有所帮助:
class Test:
x = None
@classmethod
def set_x_class(cls, value):
Test.x = value
def set_x_self(self):
self.__class__.set_x_class(10)
if __name__ == "__main__":
obj = Test()
print Test.x
obj.set_x_self()
print Test.x
obj.__class__.set_x_class(15)
print Test.x
无论如何,NlightNFotis的答案更好:在访问类方法时使用类名。它使你的代码不那么模糊。
答案 4 :(得分:0)
这似乎是一个合理的解决方案:
from __future__ import annotations
from typing import ClassVar, Dict
import abc
import string
class Cipher(abc.ABC):
@abc.abstractmethod
def encrypt(self, plaintext: str) -> str:
pass
@abc.abstractmethod
def decrypt(self, ciphertext: str) -> str:
pass
class RotateCipher(Cipher, abc.ABC):
@staticmethod
def rotate(n: int) -> str:
return string.ascii_uppercase[n:] + string.ascii_uppercase[:n]
class VigenereCipher(RotateCipher):
_TABLE: ClassVar[Dict[str, str]] = dict({(chr(i + ord("A")), RotateCipher.rotate(i)) for i in range(26)})
def encrypt(self, plaintext: str) -> str:
pass
def decrypt(self, plaintext: str) -> str:
pass
vc = VigenereCipher()
该方法现在是密码的静态方法,在类之外未引用任何内容。如果您不希望人们自己使用它,则可以改为命名RotateCipher
_RotateCipher
。
注意:在3.7上运行时,我删除了Final
,但是在阅读了Final文档之后,我认为这不会影响解决方案吗?还为缺少问题的string
添加了导入。最后,为抽象方法添加了一个实现,或者,也可以让VigenereCipher继承自abc.ABC
。
答案 5 :(得分:0)
具有add()@classmethod的人类
class Person:
def __init__(self,a,b):
self.first = a
self.second = b
@classmethod
def add(cls,a,b):
return a+b
def __repr__(self):
return ('{}'.format(Person.add(self.first,self.second)))
p = Person(10,20)
print(p)
o/p : 30