There is alot of confusion when it comes to dealing with classmethod and static method in Python. This notebook will help to clarify the use of each and help you identify places where they can be affective.
class Item(object):
rock = False
paper = True
scissor = False
def __init__(self, number):
self.number = number
@staticmethod
def static_method():
print 'This is a static method'
@classmethod
def class_method(cls):
print 'This is a class method that belongs to %s and the paper is' % cls, cls.paper
i = Item(8)
i.static_method()
i.class_method()
Item.static_method()
Item.class_method()
This is a static method This is a class method that belongs to <class '__main__.Item'> and the paper is True This is a static method This is a class method that belongs to <class '__main__.Item'> and the paper is True
This can be both invoked from instances or the class as shown above, when defining a class method the first argument must be a reference to the cls.
They can be consider simple functions that take arguments and compute something and return the result it has no information about the class or instance it was called upon. They are no different that a module level function in a file except that they invoked against an instance or class. This essentially makes their use very limited in the sense that you could just declare a module level function. Albiet they are useful for code organization and grouping. If you have static_method that is only useful associated with a particular class it makes sense to make it a static method
from datetime import datetime
def is_naive(dt):
if dt.tzinfo is None:
return True
else:
return False
class Date(object):
def __init__(self, datetime):
self.datetime = datetime
@staticmethod
def is_naive(dt):
if dt.tzinfo is None:
return True
else:
return False
from datetime import datetime
from pytz import timezone
d1 = datetime.utcnow()
d2 = d1
utc = timezone("UTC")
d1 = utc.localize(d1)
print d1
print d2
2013-02-21 04:30:18.182609+00:00 2013-02-21 04:30:18.182609
d = Date(d1)
print Date.is_naive(d1)
print Date.is_naive(d2)
print d.is_naive(d1)
print d.is_naive(d2)
print is_naive(d1)
print is_naive(d2)
False True False True False True
As we had shown above take into account some class information for example they are aware of class attributes. They can also instansiate new objects of that class type.
class Integer(object):
some_class_attributes = 'So true!'
def __init__(self, number):
self.number = number
@classmethod
def new_number(cls, number):
print cls.some_class_attributes
return cls(number) # creating new integer instance
number = Integer(5)
print number.number
5
new_number = Integer.new_number(8)
print new_number.number
So true! 8
Now lets see these work with Subclasses and what actually gets invoked
from random import choice
COLORS = ['Brown', 'Black', 'Golden']
class Animal(object):
def __init__(self, color):
self.color = color
@classmethod
def make_baby(cls):
color = choice(COLORS)
print cls
return cls(color)
@staticmethod
def speak():
print 'Roar!'
class Dog(Animal):
@staticmethod
def speak():
print 'Bark!'
@classmethod
def make_baby(cls):
print 'making dog baby'
# do something dog specific
return super(Dog, cls).make_baby()
class Cat(Animal):
pass
d = Dog('Brown')
print d.color
pup = d.make_baby()
pup
print pup.color
Brown making dog baby <class '__main__.Dog'> Golden
pup.speak()
d.speak()
Dog.speak()
Animal.speak()
Bark! Bark! Bark! Roar!
c = Cat('Red')
print c.color
kitty = c.make_baby()
print kitty.color
kitty.speak()
Red <class '__main__.Cat'> Black Roar!