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



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



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

519   6  

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)

Comments

    Ничего не найдено.