Classmethod, staticmethod, classonlymethod

最近在看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相当于一个普通函数。

它的主要作用是限定命名空间,也就是说它虽然相当于一个普通函数,但限定这个类才会使用。

参考:https://stackoverflow.com/questions/12179271/meaning-of-classmethod-and-staticmethod-for-beginner#12179752

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装饰的方法只能由类本身调用,而不能被类的实例化对象调用。

参考:https://stackoverflow.com/questions/8133312/what-is-the-difference-between-django-classonlymethod-and-python-classmethod

 

总结:

  被类调用 被实例化对象调用 需要传入类什么行业参数
classmethod 可以 可以 需要
staticmethod 可以 可以 不需要
classonlymethod 可以 不可以 需要

 

 

上一篇:工厂模式

下一篇:Django 获取model的verbose_name