web-dev-qa-db-ja.com

Python classmethod?のユースケースの例は何ですか?

Python for? のクラスメソッドとは)==を読みましたが、その投稿の例は複雑です。 Pythonのクラスメソッドの特定のユースケースの。

Python classmethodがジョブに適したツールになるような、小規模で具体的な使用例に名前を付けられますか?

58
coffee-grinder

初期化のヘルパーメソッド:

class MyStream(object):

    @classmethod
    def from_file(cls, filepath, ignore_comments=False):    
        with open(filepath, 'r') as fileobj:
            for obj in cls(fileobj, ignore_comments):
                yield obj

    @classmethod
    def from_socket(cls, socket, ignore_comments=False):
        raise NotImplemented # Placeholder until implemented

    def __init__(self, iterable, ignore_comments=False):
       ...
46
anijhaw

まあ___new___は非常に重要なクラスメソッドです。インスタンスは通常どこから来るのですか

so dict()はもちろん_dict.__new___を呼び出しますが、時々辞書を作成する別の便利な方法があります。それはclassmethod dict.fromkeys()です

例えば。

_>>> dict.fromkeys("12345")
{'1': None, '3': None, '2': None, '5': None, '4': None}
_
28
John La Rooy

私は知りません、名前付きコンストラクターメソッドのようなものですか?

class UniqueIdentifier(object):

    value = 0

    def __init__(self, name):
        self.name = name

    @classmethod
    def produce(cls):
        instance = cls(cls.value)
        cls.value += 1
        return instance

class FunkyUniqueIdentifier(UniqueIdentifier):

    @classmethod
    def produce(cls):
        instance = super(FunkyUniqueIdentifier, cls).produce()
        instance.name = "Funky %s" % instance.name
        return instance

使用法:

>>> x = UniqueIdentifier.produce()
>>> y = FunkyUniqueIdentifier.produce()
>>> x.name
0
>>> y.name
Funky 1
19
julkiewicz

私はほとんどの場合_@classmethodコードをクラスに関連付けるため、コードを使用するためにクラスのインスタンスを必要としない場合に、グローバル関数の作成を回避するため。

たとえば、キーが何らかのパターンに準拠している場合にのみキーを有効と見なすデータ構造を持つ場合があります。これをクラスの内外で使用したい場合があります。ただし、さらに別のグローバル関数を作成する必要はありません。

def foo_key_is_valid(key):
    # code for determining validity here
    return valid

このコードを、それが関連付けられているクラスとグループ化することをお勧めします。

class Foo(object):

    @classmethod
    def is_valid(cls, key):
        # code for determining validity here
        return valid

    def add_key(self, key, val):
        if not Foo.is_valid(key):
            raise ValueError()
        ..

# lets me reuse that method without an instance, and signals that
# the code is closely-associated with the Foo class
Foo.is_valid('my key')
10
samplebias

@classmethodを使用する最大の理由は、継承を目的とした代替コンストラクターにあります。これは、ポリモーフィズムで非常に役立ちます。例:

class Shape(object):
    # this is an abstract class that is primarily used for inheritance defaults
    # here is where you would define classmethods that can be overridden by inherited classes
    @classmethod
    def from_square(cls, square):
        # return a default instance of cls
        return cls()

Shapeはクラスメソッドfrom_squareを定義する抽象クラスであることに注意してください。Shapeは実際には定義されていないため、Squareから派生する方法がわからないため、単にクラスのデフォルトインスタンスを返します。

継承されたクラスは、このメソッドの独自のバージョンを定義できます。

class Square(Shape):
    def __init__(self, side=10):
        self.side = side

    @classmethod
    def from_square(cls, square):
        return cls(side=square.side)


class Rectangle(Shape):
    def __init__(self, length=10, width=10):
        self.length = length
        self.width = width

    @classmethod
    def from_square(cls, square):
        return cls(length=square.side, width=square.side)


class RightTriangle(Shape):
    def __init(self, a=10, b=10):
        self.a = a
        self.b = b
        self.c = ((a*a) + (b*b))**(.5)

    @classmethod
    def from_square(cls, square):
        return cls(a=square.length, b=square.width)


class Circle(Shape):
    def __init__(self, radius=10):
        self.radius = radius

    @classmethod
    def from_square(cls, square):
        return cls(radius=square.length/2)

使用法により、これらのインスタンス化されていないクラスをすべて多態的に扱うことができます

square = Square(3)
for polymorphic_class in (Square, Rectangle, RightTriangle, Circle):
    this_shape = polymorphic_class.from_square(square)

これはあなたが言うかもしれない素晴らしいことですが、なぜ私は@staticmethodとしてこの同じ多態的な振る舞いを達成するのに使えなかったのでしょうか:

class Circle(Shape):
    def __init__(self, radius=10):
        self.radius = radius

    @staticmethod
    def from_square(square):
        return Circle(radius=square.length/2)

答えは可能ですが、メソッドでCircleを明示的に呼び出す必要があるため、継承のメリットは得られません。つまり、オーバーライドせずに継承クラスから呼び出すと、毎回Circleを取得することになります。

実際にfrom_squareロジックをまったく持たない別のシェイプクラスを定義すると、何が得られるかに注目してください。

class Hexagon(Shape):
    def __init__(self, side=10):
        self.side = side

    # note the absence of classmethod here, this will use from_square it inherits from shape

ここで、@classmethodを未定義のままにしておくと、clsが誰であるかを保持しながらShape.from_squareのロジックを使用し、適切な形状を返します。

square = Square(3)
for polymorphic_class in (Square, Rectangle, RightTriangle, Circle, Hexagon):
    this_shape = polymorphic_class.from_square(square)
10
krayzk