class method vs static method 2017
Method is just a function object created by def statement.
Method works in exactly the same way as a simple function. But there is one exception: a method's first argument always receives the instance object:
- simple method : defined outside of a class. This function can access class attributes by feeding instance arg.
- instance method :
- class method : if we need to use class attributes
@classmethod def cfoo(cls,)
- static method : do not have any info about the class
@staticmethod def sfoo()
They have more similarities than differences.
Most of the cases, we can do the equivalent tasks with just a normal function (defined outside of a class). But in terms of software design, clean code, and effectiveness (inner workings), there is a slight difference in their usages.
In this chapter, we will discuss the difference between the class method and the static method.
There is another one called instance method but inner working of instance method is the same as the class method. Actually, Python automatically maps an instance method call to a class method. For instance, a call like this:
will be automatically converted to a class method function call like this:
Suppose we have the following class with instance method foo():
# a.py class A: message = "class message" @classmethod def cfoo(cls): print(cls.message) def foo(self, msg): self.message = msg print(self.message) def __str__(self): return self.message
Because the method foo() is designed to process instances, we normally call the method through instance:
>>> from a import A >>> a = A() >>> a.foo('instance call') instance call
When we call the method, the Python automatically replace the self with the instance object, a, and then the msg gets the string passed at the call which is 'instance call'.
Methods may be called in two ways: the first one through an instance which we did above. Another way of calling is by going through the class name as shown below:
>>> A.foo('class call') Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unbound method foo() must be called with A instance as first argument (got str instance instead)
We got the error because Python needs information about the instance. We did not provide anything about the instance. So, we should use the following form when we call a method through a class name as the error message suggested:
>>> A.foo(a, 'class call') class call
Note that we pass the instance a as an argument of the foo() method.
Calls made through the instance and the class have the exact same effect, as long as we pass the same instance object ourselves in the class form.
For a class method, we can just simply call it through class name A:
>>> A.cfoo() class message
- Bound method (instance call): To call the method we must provide an instance object explicitly as the first argument. In other words, a bound method object is a kind of object that remembers the self instance and the referenced function. So, a bound method may be called as a simple function without an instance later. Python automatically packages the instance with the function in the bound method object, so we don't need to pass an instance to cal the method. In other words, when calling a bound method object, Python provides an instance for us automatically-the instance used to create the bound method object. This means that bound method objects are usually interchangeable with simple function objects, and makes them especially useful for interfaces originally written for functions such as Callback functions.
- Unbound method (class call): Accessing a function attribute of a class by qualifying the class returns an unbound method object:
>>> Callback.changeColor <unbound method Callback.changeColor>
To call the method, we must provide an instance object explicitly as the first argument:
>>> obj2 = Callback('purple') >>> t = Callback.changeColor >>> t(obj2) purple
The t is ab unbound method object (a function in 3.0), and we pass in instance.
(Note): In Puython 3.0, the notion of unbound method has been dropped, and what we describe as an unbound method here is treated as a simple function in 3.0. For most purposes, this makes no difference to our code; either way, an instance will be passed to a method's first argument when it's called through an instance.]
>>> class Callback: ... def __init__(self, color): ... self.color = color ... def changeColor(self): ... print(self.color) ... >>> obj = Callback('red') >>> cb = obj.changeColor >>> cb() red
Accessing a function attribute of a class by qualifying an instance returns a bound method object:
>>> obj.changeColor <bound method Callback.changeColor of <__main__.Callback instance at 0x7f95ebe27f80>>
Static methods are used when we need to process data associated with classes instead of instances. A static method has no self argument and it is nested in a class and is designed to work on class attributes instead of instance attributes.
Static methods never receive an automatic self argument, whether called through a class or an instance. They usually keep track of information that spans all instances, rather than providing behavior for instances.
There have been some changes in the way how we define static method. Here, I do not want to discuss the variations from one Python version to another version, but just want to show a typical usage sample.
I'll use function decorator(@) for static method, and the syntax looks like this:
class S: @staticmethod def foo(): ...
Internally, the definition has the same effect as the name rebinding:
class S: def foo(): ... foo = staticmethod(foo)
Suppose we have a typical instance counting code like this:
# s.py class S: nInstances = 0 def __init__(self): S.nInstances = S.nInstances + 1 @staticmethod def howManyInstances(): print('Number of instances created: ', S.nInstances)
Then, we make three instances:
>>> from s import S >>> >>> a = S() >>> b = S() >>> c = S()
Now that we have static method, we can call it in two ways:
- call from class
- call from instances
>>> S.howManyInstances() ('Number of instances created: ', 3) >>> a.howManyInstances() ('Number of instances created: ', 3)
Here is a simple code that has all types of methods:
class Methods: def i_method(self,x): print(self,x) def s_method(x): print(x) def c_method(cls,x): print(cls,x) s_method = staticmethod(s_method) c_method = classmethod(c_method) obj = Methods() obj.i_method(1) Methods.i_method(obj, 2) obj.s_method(3) Methods.s_method(4) obj.c_method(5) Methods.c_method(6)
(<__main__.Methods instance at 0x7f7052d75950>, 1) (<__main__.Methods instance at 0x7f7052d75950>, 2) 3 4 (<class __main__.Methods at 0x7f7052d6d598>, 5) (<class __main__.Methods at 0x7f7052d6d598>, 6)
We get the same output from this code as well:
class Methods: def i_method(self,x): print(self,x) @staticmethod def s_method(x): print(x) @classmethod def c_method(cls,x): print(cls,x) obj = Methods() obj.i_method(1) Methods.i_method(obj, 2) obj.s_method(3) Methods.s_method(4) obj.c_method(5) Methods.c_method(6)
Ph.D. / Golden Gate Ave, San Francisco / Seoul National Univ / Carnegie Mellon / UC Berkeley / DevOps / Deep Learning / Visualization