Instance, class and static methods: what each one receives, and how a call is turned into a function call.
# instance method
class Calculator:
def add(self, a, b):
return a + b
calc = Calculator()
calc.add(5, 3)
# ans: 8
selfa = 5, b = 3
# class method
class Dog:
count = 0
def __init__(self):
Dog.count += 1
@classmethod
def get_count(cls):
return cls.count
Dog().get_count()
# ans: 1
Dog() makes a dog...__init__ bumps the shared countercls, even when called on an instance
# static method
class MathUtils:
@staticmethod
def add(a, b):
return a + b
MathUtils.add(5, 3)
# ans: 8 (no instance needed)
self, no cls
# self accesses the instance
class Person:
def __init__(self, name):
self.name = name
def greet(self):
return f"Hi, I'm {self.name}"
Person("Alice").greet()
# ans: "Hi, I'm Alice"
name is "Alice"selfself.name reads the object's own attribute| Kind | First parameter | Use it for |
|---|---|---|
| instance method | self: the object | reading and changing one object's data |
@classmethod | cls: the class | class-wide data, alternative constructors |
@staticmethod | nothing | helpers that belong with the class but need neither |
Predict each result, then press → to check.
# classmethod vs instance?
class MyClass:
@classmethod
def method(cls):
return cls
MyClass.method()
# ans: <class '__main__.MyClass'>
# staticmethod access?
class MyClass:
x = 5
@staticmethod
def method():
return x
MyClass.method()
# ans: NameError (no self or cls to reach x through)
Class attributes aren't in scope inside methods; it would need MyClass.x.
# what does a classmethod receive?
class MyClass:
@classmethod
def method(cls):
return type(cls)
MyClass.method()
# ans: <class 'type'>
A class is itself an object, and its type is type.
# call an instance method on the class?
class MyClass:
def method(self):
pass
MyClass.method()
# ans: TypeError (missing self)
self: missing 1 required argument
# staticmethod with self?
class MyClass:
@staticmethod
def method(self):
pass
obj = MyClass()
obj.method()
# ans: TypeError (no implicit self)
self is missing
# classmethod inheritance?
class Base:
@classmethod
def who(cls):
return cls.__name__
class Derived(Base):
pass
Derived.who()
# ans: "Derived"
cls is the class the method was called on, not the one it was written in.
# method chaining?
class Builder:
def set_x(self, x):
self.x = x
return self
def set_y(self, y):
self.y = y
return self
Builder().set_x(1).set_y(2)
# ans: a Builder with x=1 and y=2 (each setter returns self)
# private method?
class MyClass:
def __private(self):
pass
obj = MyClass()
obj.__private()
# ans: AttributeError (name mangling)
Inside the class, __private is renamed _MyClass__private.
# method vs function?
class MyClass:
def method(self):
pass
type(MyClass.method)
# ans: <class 'function'>
type(MyClass().method)
# ans: <class 'method'>
Looked up on an object, the function is bound: it remembers the object to pass as self.
# alternative constructor?
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
@classmethod
def origin(cls):
return cls(0, 0)
Point.origin()
# ans: a new Point with x=0, y=0
obj.m(a)is Class.m(obj, a): the object becomes self.
@classmethodReceives the class as cls; great for alternative constructors.
@staticmethodReceives nothing extra.
__nameDouble underscores trigger name mangling.