What do these mean to you: @classmethod
, @staticmethod
, @property
?
Answer Background Knowledge:
These are decorators. A decorator is a special kind of function that either takes a function and returns a function, or takes a class and returns a class. The @
symbol is just syntactic sugar that allows you to decorate something in a way that's easy to read.
@my_decorator
def my_func(stuff):
do_things
Is equivalent to
def my_func(stuff):
do_things
my_func = my_decorator(my_func)
You can find a tutorial on how decorators in general work here.
Actual Answer:
The decorators @classmethod
, @staticmethod
and @property
are used on functions defined within classes. Here is how they behave:
class MyClass(object):
def __init__(self):
self._some_property = "properties are nice"
self._some_other_property = "VERY nice"
def normal_method(*args,**kwargs):
print("calling normal_method({0},{1})".format(args,kwargs))
@classmethod
def class_method(*args,**kwargs):
print("calling class_method({0},{1})".format(args,kwargs))
@staticmethod
def static_method(*args,**kwargs):
print("calling static_method({0},{1})".format(args,kwargs))
@property
def some_property(self,*args,**kwargs):
print("calling some_property getter({0},{1},{2})".format(self,args,kwargs))
return self._some_property
@some_property.setter
def some_property(self,*args,**kwargs):
print("calling some_property setter({0},{1},{2})".format(self,args,kwargs))
self._some_property = args[0]
@property
def some_other_property(self,*args,**kwargs):
print("calling some_other_property getter({0},{1},{2})".format(self,args,kwargs))
return self._some_other_property
o = MyClass()
# undecorated methods work like normal, they get the current instance (self) as the first argument
o.normal_method
# >
o.normal_method()
# normal_method((<__main__.MyClass instance at 0x7fdd2537ea28>,),{})
o.normal_method(1,2,x=3,y=4)
# normal_method((<__main__.MyClass instance at 0x7fdd2537ea28>, 1, 2),{'y': 4, 'x': 3})
# class methods always get the class as the first argument
o.class_method
# >
o.class_method()
# class_method((,),{})
o.class_method(1,2,x=3,y=4)
# class_method((, 1, 2),{'y': 4, 'x': 3})
# static methods have no arguments except the ones you pass in when you call them
o.static_method
#
o.static_method()
# static_method((),{})
o.static_method(1,2,x=3,y=4)
# static_method((1, 2),{'y': 4, 'x': 3})
# properties are a way of implementing getters and setters. It's an error to explicitly call them
# "read only" attributes can be specified by creating a getter without a setter (as in some_other_property)
o.some_property
# calling some_property getter(<__main__.MyClass instance at 0x7fb2b70877e8>,(),{})
# 'properties are nice'
o.some_property()
# calling some_property getter(<__main__.MyClass instance at 0x7fb2b70877e8>,(),{})
# Traceback (most recent call last):
# File "", line 1, in
# TypeError: 'str' object is not callable
o.some_other_property
# calling some_other_property getter(<__main__.MyClass instance at 0x7fb2b70877e8>,(),{})
# 'VERY nice'
# o.some_other_property()
# calling some_other_property getter(<__main__.MyClass instance at 0x7fb2b70877e8>,(),{})
# Traceback (most recent call last):
# File "", line 1, in
# TypeError: 'str' object is not callable
o.some_property = "groovy"
# calling some_property setter(<__main__.MyClass object at 0x7fb2b7077890>,('groovy',),{})
o.some_property
# calling some_property getter(<__main__.MyClass object at 0x7fb2b7077890>,(),{})
# 'groovy'
o.some_other_property = "very groovy"
# Traceback (most recent call last):
# File "", line 1, in
# AttributeError: can't set attribute
o.some_other_property
# calling some_other_property getter(<__main__.MyClass object at 0x7fb2b7077890>,(),{})
# 'VERY nice'