すべての静的メンバーを管理する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
どんな助けでもありがたいです!
よろしくお願いします、Volker
その時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
同様にクラス名を追加して、クラスメソッドを呼び出します。
_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
を返します
クラスがまだ完全に定義されていないため、a classmethod
in the class
definitionを呼び出すことはできません。そのため、最初のcls
argument ...クラシックなチキンとしてメソッドを渡す必要はありません-と卵の問題。ただし、メタクラスのthe__new__()
methodをオーバーロードし、以下に示すようにクラスが作成された後にそこから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
あなたの質問をもう一度読んだ後慎重に今回は2つの解決策を考えることができます。 1つ目は、ボーグデザインパターンを適用することです。 2つ目は、クラスメソッドを破棄し、代わりにモジュールレベルの関数を使用することです。これはあなたの問題を解決するようです:
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の答えはより良いものです。クラスメソッドにアクセスするときはクラス名を使用してください。これにより、コードがわかりやすくなります。
これは合理的な解決策のようです:
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
代わりに、人々がそれを単独で使用したくない場合。
注:Final
を削除しました。これは3.7で実行したためですが、Finalのドキュメントを読んだ後、ソリューションに影響を与えるとは思いませんか?質問が欠落していたstring
のインポートも追加しました。そして最後に、抽象メソッドの実装を追加しました。あるいは、VigenereCipherがabc.ABC
同様に。