Каков пример использования для Python classmethod?

Я читал для чего существуют методы класса в Python? но примеры в этом посте сложные. Я ищу ясный, простой, голый пример конкретного варианта использования для classmethods в Python.

можете ли вы назвать небольшой конкретный пример использования, где Python classmethod будет правильным инструментом для задания?

6 ответов


вспомогательные методы для инициализации:

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):
       ...

хорошо __new__ является довольно важным classmethod. Это где экземпляры обычно приходят из

так dict() звонки dict.__new__ конечно, но есть еще один удобный способ сделать диктовки иногда, который является classmethod dict.fromkeys()

например.

>>> dict.fromkeys("12345")
{'1': None, '3': None, '2': None, '5': None, '4': None}

Я не знаю, что-то вроде названные методы конструктор?

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

Я нахожу, что я чаще всего использую @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')

самая большая причина для использования @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 является абстрактным классом, который определяет classmethod 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 undefined и он будет использовать логику из Shape.from_square при сохранении, кто cls is и возвращает соответствующую форму.

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

in class MyClass(object):
    '''
    classdocs
    '''
    obj=0
    x=classmethod
    def __init__(self):
        '''
        Constructor
        '''
        self.nom='lamaizi'
        self.prenom='anas'
        self.age=21
        self.ville='Casablanca'
if __name__:
    ob=MyClass()
    print(ob.nom)
    print(ob.prenom)
    print(ob.age)
    print(ob.ville)