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

Posted on

Question :

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

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 for classmethods in Python.

Can you name a small, specific example use case where a Python classmethod would be the right tool for the job?

Answer #1:

Helper methods for initialization:

class MyStream(object):

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

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

    def __init__(self, iterable, ignore_comments=False):
Answered By: anijhaw

Answer #2:

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


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

Answer #3:

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

class UniqueIdentifier(object):

    value = 0

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

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

class FunkyUniqueIdentifier(UniqueIdentifier):

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


>>> x = UniqueIdentifier.produce()
>>> y = FunkyUniqueIdentifier.produce()
>>> x.name
>>> y.name
Funky 1
Answered By: julx

Answer #4:

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

    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

    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)

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

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

    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

    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)
Answered By: krayzk

Answer #5:

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

    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')
Answered By: samplebias

Answer #6:

in class MyClass(object):
    def __init__(self):
if __name__:
Answered By: anas lamaizi

Leave a Reply

Your email address will not be published. Required fields are marked *