What's an example use case for a Python classmethod?

后端 未结 6 1408
傲寒
傲寒 2020-12-04 07:31

I\'ve read What are Class methods in Python for? but the examples in that post are complex. I am looking for a clear, simple, bare-bones example of a particular use case fo

相关标签:
6条回答
  • 2020-12-04 07:59

    Helper methods for initialization:

    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):
           ...
    
    0 讨论(0)
  • 2020-12-04 08:10
    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)
    
    0 讨论(0)
  • 2020-12-04 08:12

    Well __new__ is a pretty important classmethod. It's where instances usually come from

    so dict() calls dict.__new__ of course, but there is another handy way to make dicts sometimes which is the classmethod dict.fromkeys()

    eg.

    >>> dict.fromkeys("12345")
    {'1': None, '3': None, '2': None, '5': None, '4': None}
    
    0 讨论(0)
  • 2020-12-04 08:12

    I don't know, something like named constructor methods?

    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
    

    Usage:

    >>> x = UniqueIdentifier.produce()
    >>> y = FunkyUniqueIdentifier.produce()
    >>> x.name
    0
    >>> y.name
    Funky 1
    
    0 讨论(0)
  • 2020-12-04 08:19

    I find that I most often use @classmethod to associate a piece of code with a class, to avoid creating a global function, for cases where I don't require an instance of the class to use the code.

    For example, I might have a data structure which only considers a key valid if it conforms to some pattern. I may want to use this from inside and outside of the class. However, I don't want to create yet another global function:

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

    I'd much rather group this code with the class it's associated with:

    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')
    
    0 讨论(0)
  • 2020-12-04 08:25

    The biggest reason for using a @classmethod is in an alternate constructor that is intended to be inherited. This can be very useful in polymorphism. An example:

    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()
    

    Notice that Shape is an abstract class that defines a classmethod from_square, since Shape is not really defined, it does not really know how to derive itself from a Square so it simply returns a default instance of the class.

    Inherited classes are then allowed to define their own versions of this method:

    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)
    

    The usage allows you to treat all of these uninstantiated classes polymorphically

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

    This is all fine and dandy you might say, but why couldn't I just use as @staticmethod to accomplish this same polymorphic behavior:

    class Circle(Shape):
        def __init__(self, radius=10):
            self.radius = radius
    
        @staticmethod
        def from_square(square):
            return Circle(radius=square.length/2)
    

    The answer is that you could, but you do not get the benefits of inheritance because Circle has to be called out explicitly in the method. Meaning if I call it from an inherited class without overriding, I would still get Circle every time.

    Notice what is gained when I define another shape class that does not really have any custom from_square logic:

    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
    

    Here you can leave the @classmethod undefined and it will use the logic from Shape.from_square while retaining who cls is and return the appropriate shape.

    square = Square(3)
    for polymorphic_class in (Square, Rectangle, RightTriangle, Circle, Hexagon):
        this_shape = polymorphic_class.from_square(square)
    
    0 讨论(0)
提交回复
热议问题