zoukankan      html  css  js  c++  java
  • Python 中的 classmethod 和 staticmethod 有什么具体用途?

    作者:李保银
    链接:https://www.zhihu.com/question/20021164/answer/18224953
    来源:知乎
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    普通方法,静态方法和类方法

    这个答案的原文是Difference between @staticmethod and @classmethod in Python
    这里的内容是我通知原作者并得到允许的情况下的翻译稿
    这个是我的博客文章的地址pyhton静态方法和类方法
    类中最常用的方法是实例方法, 即通过通过实例作为第一个参数的方法。
    举个例子,一个基本的实例方法就向下面这个:

     
    class Kls(object):
        def __init__(self, data):
            self.data = data
        def printd(self):
            print(self.data)
    ik1 = Kls('arun')
    ik2 = Kls('seema')
    ik1.printd()
    ik2.printd()
    

    这会给出如下的输出:
    arun
    seema



    然后看一下代码和示例图片:
    • 1,2参数传递给方法.
    • 3 self参数指向当前实例自身.
    • 4 我们不需要传递实例自身给方法,Python解释器自己会做这些操作的.

    如果现在我们想写一些仅仅与类交互而不是和实例交互的方法会怎么样呢? 我们可以在类外面写一个简单的方法来做这些,但是这样做就扩散了类代码的关系到类定义的外面. 如果像下面这样写就会导致以后代码维护的困难:

     
    def get_no_of_instances(cls_obj):
        return cls_obj.no_inst
    class Kls(object):
        no_inst = 0
        def __init__(self):
            Kls.no_inst = Kls.no_inst + 1
    ik1 = Kls()
    ik2 = Kls()
    print(get_no_of_instances(Kls))
    

    输出:
    2
    @classmethod
    我们要写一个只在类中运行而不在实例中运行的方法. 如果我们想让方法不在实例中运行,可以这么做:

     
    def iget_no_of_instance(ins_obj):
        return ins_obj.__class__.no_inst
    class Kls(object):
        no_inst = 0
        def __init__(self):
        Kls.no_inst = Kls.no_inst + 1
    ik1 = Kls()
    ik2 = Kls()
    print iget_no_of_instance(ik1)
    

    输出
    2
    在Python2.2以后可以使用@classmethod装饰器来创建类方法.

     
    class Kls(object):
        no_inst = 0
        def __init__(self):
            Kls.no_inst = Kls.no_inst + 1
        @classmethod
        def get_no_of_instance(cls_obj):
            return cls_obj.no_inst
    ik1 = Kls()
    ik2 = Kls()
    print ik1.get_no_of_instance()
    print Kls.get_no_of_instance()
    

    输出:
    2
    2
    这样的好处是: 不管这个方式是从实例调用还是从类调用,它都用第一个参数把类传递过来.
    @staticmethod
    经常有一些跟类有关系的功能但在运行时又不需要实例和类参与的情况下需要用到静态方法. 比如更改环境变量或者修改其他类的属性等能用到静态方法. 这种情况可以直接用函数解决, 但这样同样会扩散类内部的代码,造成维护困难.
    比如这样:

     
    IND = 'ON'
    def checkind():
        return (IND == 'ON')
    class Kls(object):
         def __init__(self,data):
            self.data = data
    def do_reset(self):
        if checkind():
            print('Reset done for:', self.data)
    def set_db(self):
        if checkind():
            self.db = 'new db connection'
            print('DB connection made for:',self.data)
    ik1 = Kls(12)
    ik1.do_reset()
    ik1.set_db()
    

    输出:
    Reset done for: 12
    DB connection made for: 12
    如果使用@staticmethod就能把相关的代码放到对应的位置了.
     
    IND = 'ON'
    class Kls(object):
        def __init__(self, data):
            self.data = data
        @staticmethod
        def checkind():
            return (IND == 'ON')
        def do_reset(self):
            if self.checkind():
                print('Reset done for:', self.data)
        def set_db(self):
            if self.checkind():
                self.db = 'New db connection'
            print('DB connection made for: ', self.data)
    ik1 = Kls(12)
    ik1.do_reset()
    ik1.set_db()
    

    输出:
    Reset done for: 12
    DB connection made for: 12
    下面这个更全面的代码和图示来展示这两种方法的不同
    @staticmethod 和 @classmethod的不同

     
    class Kls(object):
        def __init__(self, data):
            self.data = data
        def printd(self):
            print(self.data)
        @staticmethod
        def smethod(*arg):
            print('Static:', arg)
        @classmethod
        def cmethod(*arg):
            print('Class:', arg)
     
    >>> ik = Kls(23)
    >>> ik.printd()
    23
    >>> ik.smethod()
    Static: ()
    >>> ik.cmethod()
    Class: (<class '__main__.Kls'>,)
    >>> Kls.printd()
    TypeError: unbound method printd() must be called with Kls instance as first argument (got nothing instead)
    >>> Kls.smethod()
    Static: ()
    >>> Kls.cmethod()
    Class: (<class '__main__.Kls'>,)
    

    下面这个图解释了以上代码是怎么运行的:
  • 相关阅读:
    快速开始
    阿里为什么选择RocketMQ
    4 分布式消息队列的协调者
    9 首个Apache中间件顶级项目
    3、用适合的方式发送和接收消息
    2 生产环境下的配置和使用
    TOMCAT加载两次war包(重复加载)
    Google Protocol Buffer 的使用(二)
    Google Protocol Buffer 的使用(一)
    PostgreSQL及PostGIS使用
  • 原文地址:https://www.cnblogs.com/wangmo/p/7772982.html
Copyright © 2011-2022 走看看