zoukankan      html  css  js  c++  java
  • python @classmethod 和 @staticmethod区别,以及类中方法参数cls和self的区别

    staticmethod

    首先来看@staticmethod,这个装饰器很好理解,就是让类中的方法变成一个普通的函数(因为是普通函数,并没有绑定在任何一个特定的类或者实例上。所以与不需要对象实例化就可以直接调用)。可以使用类或者类的实例调用,并且没有任何隐含参数的传入,所以不需要self(参数名是随便定的)。

    >>> class C(object):
    ...     @staticmethod
    ...     def add(a,b):
    ...             return a+b
    ...     def get_weight(self):
    ...             return self.add(1,2)
    ... 
    >>> C.add
    <function add at 0x1d32668>
    >>> C().add
    <function add at 0x1d32668>
    >>> C.get_weight
    <unbound method C.get_weight>

    总结:

    1、当一个函数逻辑上属于一个类又不依赖与类的属性的时候,可以使用 @staticmethod。

    2、使用 @staticmethod 可以避免每次使用的时都会创建一个对象的开销。

    3、@staticmethod 可以使用类和类的实例调用。但是不依赖于类和类的实例的状态。

    classmethod

    再看@classmethod,我们对比下加与不加装饰前后函数

    不加装饰前

    >>> class C(object):
    ...     weight = 12
    ...     def get_weight(self):
    ...             print self
    ... 
    >>> C.get_weight
    <unbound method C.get_weight>
    >>> C().get_weight
    <bound method C.get_weight of <__main__.C object at 0x25d7b10>>
    >>> C().get_weight()
    <__main__.C object at 0x25d7a50>
    >>> myc = C()
    >>> myc.get_weight
    <bound method C.get_weight of <__main__.C object at 0x25d7a50>>
    >>> myc.get_weight()
    <__main__.C object at 0x25d7a50>

    通过例子知道,C().get_weight和myc.get_weight都是绑定在对象C的一个实例上的。(e.g. <bound method C.get_weight of <__main__.C object at 0x25d7b10>>)

    顺便通过下面的代码,看下get_weight的self到底接收的是什么:

    #继续上面的代码
    >>> C.get_weight() #异常报错 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unbound method get_weight() must be called with C instance as first argument (got nothing instead) >>> C.get_weight(C()) #将C的一个实例显示传递给self <__main__.C object at 0x25d7b50> >>> myc.get_weight() #myc.get_weight()隐藏了第一个参数myc <__main__.C object at 0x25d7a50> >>>

    调用的实例隐藏的作为一个参数self传递过去了,self 只是一个普通的参数名称(参数名是随便定的),不是关键字。

    加@classmethod装饰后

    >>> class C(object):
    ...     weight = 12
    ...     @classmethod
    ...     def get_weight(cls):
    ...             print cls
    ... 
    >>> C.get_weight
    <bound method type.get_weight of <class '__main__.C'>>
    >>> C().get_weight
    <bound method type.get_weight of <class '__main__.C'>>
    >>> myc = C()
    >>> myc.get_weight
    <bound method type.get_weight of <class '__main__.C'>>
    >>> myc.get_weight()
    <class '__main__.C'>
    >>> C.get_weight()
    <class '__main__.C'>

    可以看出,C类和C类的实例都能调用 get_weight 而且调用结果完全一样。 我们看到 weight 是属于 C类的属性,当然也是C的实例的属性(元对象__get__机制)。

    再看一下get_weight的参数cls到底接收的是什么,可以看到C.get_weight()和myc.get_weight()接收的都是C类(e.g. <class '__main__.C'> )而不是C类的实例,cls只是一个普通的函数参数,调用时隐含的传递过去。

    总结:

    1、classmethod 是类对象与函数的结合。

    2、可以使用类和类的实例调用,但是都是将类作为隐含参数传递过去。

    3、使用类来调用 classmethod 可以避免将类实例化的开销。

    ==============================================================================

    补充:

    @staticmethod 装饰器会让 foo 的 __get__ 返回一个函数,而不是一个方法。看下面的例子

    >>> class C(object):
    ...     def foo(self):
    ...         pass
    ...
    >>> C.foo
    <unbound method C.foo>
    >>> C().foo
    <bound method C.foo of <__main__.C object at 0xb76ddcac>>
    >>>

    所谓 bound method ,就是方法对象的第一个函数参数绑定为了这个类的实例(所谓 bind )。这也是那个 self 的由来。

    那,我们加入@staticmethod之后:

    >>> class C(object):
    ...     @staticmethod
    ...     def foo():
    ...         pass
    ...
    >>> C.foo
    <function foo at 0xb76d056c>
    >>> C.__dict__['foo'].__get__(None, C)
    <function foo at 0xb76d056c>

    装饰器会让 foo 的 __get__ 返回一个函数,而不是一个方法。

    参考资料:

    Stackoverflow上的Python问题精选 http://pyzh.readthedocs.org/en/latest/python-questions-on-stackoverflow.html#id14

    Python中的method http://blog.jobbole.com/53989/

    python中的元类编程 http://www.ibm.com/developerworks/cn/linux/l-pymeta/index.html

  • 相关阅读:
    java基础部分的一些有意思的东西。
    antdvue按需加载插件babelpluginimport报错
    阿超的烦恼 javaScript篇
    .NET E F(Entity Framework)框架 DataBase First 和 Code First 简单用法。
    JQuery获得input ID相同但是type不同的方法
    gridview的删除,修改,数据绑定处理
    jgGrid数据格式
    Cannot read configuration file due to insufficient permissions
    Invoke action which type of result is JsonResult on controller from view using Ajax or geJSon
    Entity model数据库连接
  • 原文地址:https://www.cnblogs.com/kennyhr/p/3935465.html
Copyright © 2011-2022 走看看