分享 | 交流
让学习成为一种习惯

Python 中的 @classmethod 和 @staticmethod 有什么具体用途?

以下先引用别人总结的两句话来做开头引导

@classmethod意思是:当这个方法被调用时,我们传递类作为第一个参数,而不是那个类的实例(就像我们通常用方法做的那样)。这意味着您可以在该方法内使用该类及其属性,而不是特定的实例。
@staticmethod意思是:当这个方法被调用时,我们不会传递一个类的实例给它(就像我们通常用方法做的那样)。这意味着你可以在一个类中放入一个函数,但你不能访问该类的实例(当你的方法不使用实例时这很有用)

类中最常用的方法是实例方法, 即通过通过实例作为第一个参数的方法。
举个例子,一个基本的实例方法就向下面这个:

 
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

Python 中的 classmethod 和 staticmethod 有什么具体用途?

然后看一下代码和示例图片:

  • 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\'>,)

下面这个图解释了以上代码是怎么运行的:

Python 中的 classmethod 和 staticmethod 有什么具体用途?

 

未经允许不得转载:留时刻运维网 » Python 中的 @classmethod 和 @staticmethod 有什么具体用途?

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

留时刻 - Linux系统教程,运维经验分享

加入我们给我留言