Lesson 8 of 10
Alternative constructors
- 12 min
- 6 checks
- 3 hints
- Go to task
Goal
A clearly named constructor for each kind of input
Explanation
__init__ is one way to create an object, but data arrives in many shapes: a string like "1.4.2" from a config file, or a dict from JSON. Try to handle them all inside it and it fills up with isinstance checks. The alternative is to add other ways to create the object, with clear names, like Version.from_string("1.4.2").
That's what @classmethod does. The method receives the class itself in cls instead of the object, so it can parse the input and return cls(...). @staticmethod goes on a function that needs neither self nor cls but belongs to the class, so you write it inside, like a function that checks a string is valid before parsing it.
The trap is writing return Version(...) inside the class method. It works today, then someone subclasses it and gets a Version from from_string instead of an object of their own class. cls is whichever class the method was actually called on.
Your task
Give Version a staticmethod is_valid(text) that accepts only three numbers separated by dots, and a classmethod from_string(text) that raises ValueError when the text is invalid and returns an instance of cls.
Checks
6 checks- from_string parses the string into numbers
- A subclass gets an object of its own type
- from_string raises ValueError for invalid text
- is_valid accepts a correct version
- is_valid rejects incomplete and non-numeric text
- is_valid works on an instance too