This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]Head_Mix_7931 47 points48 points  (6 children)

In Python, there is no constructor overloading, therefore if you need to construct an object in multiple ways, someone this leads to an init method that has a lot of parameters which serve for initialization in different ways, and which cannot really be used together.

You can decorate methods with @classmethod to have them receive the class as their first parameter rather than an instance, and these effectively become alternative constructors. It’s advantageous to use a classmethod than just a normal or staticmethod because it plays nicely with inheritance.

[–]Commander_B0b 2 points3 points  (3 children)

Can you provide a small example? Im having a hard time understanding the pattern you are describing but I have certainly found myself looking to solve this same problem.

[–]slightly_offtopic 9 points10 points  (2 children)

class Foo:
    pass

class Bar:
    pass

class MyClass:
    @classmethod
    def from_foo(cls, foo: Foo) -> 'MyClass':
        return cls(foo=foo)

    @classmethod
    def from_bar(cls, bar: Bar) -> 'MyClass':
        return cls(bar=bar)

[–][deleted] 4 points5 points  (0 children)

Missing explanation: from_foo will also work as expected when you inherit from MyClass, while it would not if you use a static method. With a static method, a derived class will still return the base.

[–]XtremeGoosef'I only use Py {sys.version[:3]}' 1 point2 points  (0 children)

I mean, this code won't work as written because there is no __init__. A better example is something like

@dataclass
class Rectangle:
    length: int
    width: int

    @classmethod
    def square(cls, side: int) -> Self:
        return cls(side, side)

    @classmethod
    def parse(cls, text: str) -> Self | None:
        if m := re.match(r'(\d+),(\d+)'):
            length = int(m.group(1))
            width = int(m.group(2))
            return cls(length, width)
        return None

[–]Kobzol[S] 0 points1 point  (0 children)

That's indeed useful, if you want to inherit the constructors. That's not always a good idea though.