39

とりわけ静的メンバーを管理するクラスを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

4

7 に答える 7

36

あなたの例で実行された時点でx=10は、クラスが存在しないだけでなく、classmethodも存在しません。

Pythonでの実行は上から下に進みます。がclassmethodの上にある場合x=10、まだ定義されていないため、その時点で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
于 2012-12-16T11:32:06.717 に答える
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

于 2012-12-16T10:51:31.603 に答える
4

クラスがまだ完全に定義されていないためclassmethod、定義でaを呼び出すことはできません。したがって、最初の引数としてメソッドを渡すことはできません...古典的な鶏が先か卵が先かという問題です。ただし、この制限を回避するには、メタクラスのメソッドをオーバーロードし、以下に示すように、クラスが作成された後にそこからclassmethodを呼び出します。classcls__new__()

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
于 2012-12-16T12:11:34.027 に答える
2

今回、あなたの質問を注意深く読み直した後、私は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の答えはより良いものです:クラスメソッドにアクセスするときにクラス名を使用します。これにより、コードがわかりにくくなります。

于 2012-12-16T11:12:11.727 に答える
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人々がそれを単独で使用したくない場合は、代わりに名前を付けることを選択できます。

注:Finalこれを3.7で実行したため、を削除しましたが、Finalのドキュメントを読んだ後、ソリューションに影響を与えるとは思いませんか?stringまた、質問が欠落しているインポートを追加しました。そして最後に、抽象メソッドの実装を追加しました。あるいは、VigenereCipherに継承させることもできabc.ABCます。

于 2019-12-25T01:48:08.267 に答える
0

add()@classmethodを使用したpersonクラス

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
于 2020-11-22T06:55:54.313 に答える
0

classmethodがあまり頻繁に使用されない場合は、遅延評価を実行してください

class A() {
   # this does not work: x=A.initMe()

   @classmethod
   def initMe(cls) {
     if not hasattr(cls,"x"):
        # your code her
        cls.x=# your result
        pass

   @classmethod
   def f1(cls) {
      # needs initMe
      cls.initMe()
      # more code using cls.x
   }

}
于 2021-11-14T18:28:22.230 に答える