@classmethod & @staticmethod in Python
Class Methods: @classmethod
In Object Oriented Python, an instance method perceives its argument as the object on which the method is being called. It can operate on class attributes as well as instance attributes. Here's an example:
>>> class Toy: '''Toy class''' count = 0 def __init__(self, name, color): '''sets instance attributes to provided values; increments counter and prints it.''' self.name = name self.color = color Toy.count += 1 print("Toys manufactured so far:", Toy.count) >>> woody = Toy('Woody', 'Brown') Toys manufactured so far: 1 >>> buzz = Toy('Buzz Lightyear', 'White & Purple') Toys manufactured so far: 2
@classmethod: A method following the @classmethod decorator will perceive its first argument to be the class, and not the instance. The @classmethod decorator denotes a method that operates on the class attributes rather than instance attributes. Let's segregate the initializiation and count increment operation into two different methods to demonstrate this.
>>> class Toy: '''Toy class''' count = 0 def __init__(self, name, color): '''sets instance attributes to provided values; increments counter and prints it.''' self.name = name self.color = color self.incrementCount() @classmethod def incrementCount(cls): cls.count += 1 print("Toys manufactured so far:", cls.count) >>> woody = Toy('Woody', 'Brown') Toys manufactured so far: 1 >>> buzz = Toy('Buzz Lightyear', 'White & Purple') Toys manufactured so far: 2
Note that the class method can be invoked by the object as well. We can call it using the Toy.incrementCount() notation as well, but that would defeat the purpose of the example. Also, the argument can be called anything apart from 'cls', it makes more sense to call it something that is synonymous to the word 'class' (remember, class is a keyword).
Static Methods: @staticmethod
In Object Oriented Python, an instance method perceives its argument as the object on which the method is being called. It can operate on class attributes as well as instance attributes. I'll cite the example I used while demonstrating the @classmethod decorator.
>>> class Toy: '''Toy class''' count = 0 def __init__(self, name, color): '''sets instance attributes to provided values; increments counter and prints it.''' self.name = name self.color = color Toy.count += 1 print("Toys manufactured so far:", Toy.count) >>> woody = Toy('Woody', 'Brown') Toys manufactured so far: 1 >>> buzz = Toy('Buzz Lightyear', 'White & Purple') Toys manufactured so far: 2
@staticmethod: A method following the @staticmethod decorator will NOT perceive its first argument to be the class or the instance. Rather, it will take the first argument to mean a regular positional argument. This is used to denote utility methods, which belong in the class code, but don't operate on the instance or the class. In the below example, checkForName() performs a validation, something like a utility method. It does not operate the instance or the class, and hence neither of these needs to be passes as an argument to it.
>>> class Toy: '''Toy class''' count = 0 def __init__(self, name, color): '''sets instance attributes to provided values; increments counter and prints it.''' self.name = name self.color = color self.checkForName(self.name) @staticmethod def checkForName(name): if name.startswith('w') or name.startswith('W'): print("Hey! This is a random check to see if your name begins with 'W', and it does!") else: print("Oh no! Your name does not start with W, you just missed out on a goodie!") >>> woody = Toy('Woody', 'Brown') Hey! This is a random check to see if your name begins with 'W', and it does! >>> buzz = Toy('Buzz Lightyear', 'White & Purple') Oh no! Your name does not start with W, you just missed out on a goodie!