最近在看DRF源码中的GenericViewset时注意到classonlymethod的装饰器,一下回想起classmethod, staticmethod,这里顺便回忆下:
class ViewSetMixin:
"""
This is the magic.
Overrides `.as_view()` so that it takes an `actions` keyword that performs
the binding of HTTP methods to actions on the Resource.
For example, to create a concrete view binding the 'GET' and 'POST' methods
to the 'list' and 'create' actions...
view = MyViewSet.as_view({'get': 'list', 'post': 'create'})
"""
@classonlymethod
def as_view(cls, actions=None, **initkwargs):
pass
看到ViewSetMixin重写了as_view方法,这与它的用法有关,这里不作介绍 。
先说区别:
classonlymethod只能被类调用:不能被实例化对象调用。
classmethod则是类专属的,可以通过类名调用,也可以通过实例化对象调用
staticmethod是静态方法
classmethod
class Method(object):
@classmethod
def no_need_obj(self):
print('no need obj!')
def need_obj(self):
print('need obj')
m = Method()
m.no_need_obj()
m.need_obj()
Method.no_need_obj()
Method.need_obj()
#结果:
no need obj!
need obj
no need obj!
Traceback (most recent call last):
File "code.py", line 17, in <module>
Method.need_obj()
TypeError: need_obj() missing 1 required positional argument: 'self'
可以看到被classmethod装饰的方法既可以通过类名调用也可以通过实例调用,而没有被装饰的方法必须通过实例化对象调用,否则报错,需要传入实例化对象。
staticmethod
我们对上面的代码稍作修改:
class Method(object):
@classmethod
def no_need_obj(self):
print('no need obj!')
@staticmethod
def need_obj():
print('need obj')
m = Method()
m.no_need_obj()
m.need_obj()
Method.no_need_obj()
Method.need_obj()
# 结果:
no need obj!
need obj
no need obj!
need obj
可以看到在调用被staticmethod装饰的need_obj时,没有self参数,在这里need_obj相当于一个普通函数。
它的主要作用是限定命名空间,也就是说它虽然相当于一个普通函数,但限定这个类才会使用。
classonlymethod
在django中的原码:
class classonlymethod(classmethod):
def __get__(self, instance, owner):
if instance is not None:
raise AttributeError("This method is available only on the view class.")
return super(classonlymethod, self).__get__(instance, owner)
可以看到如果有实例对象,是会报错的。因为classonlymethod装饰的方法只能由类本身调用,而不能被类的实例化对象调用。
总结:
被类调用 | 被实例化对象调用 | 需要传入类什么行业参数 | |
classmethod | 可以 | 可以 | 需要 |
staticmethod | 可以 | 可以 | 不需要 |
classonlymethod | 可以 | 不可以 | 需要 |