pyhton静态方法和类方法

Python中的类方法和静态方法

本文是这个文章的翻译
在这个文章中我会尝试解释一下Python的类方法和静态方法,以及它们之将的不同。类方法和静态方法都是使用装饰器定义的。

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

类中最常用的方法是实例方法, 即通过通过实例作为第一个参数的方法。

举个例子,一个基本的实例方法就向下面这个:

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

e5f0b2c9-4d18-478e-89d2-bfdd4de7c13d
然后看一下代码和示例图片:

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

下面这个图解释了以上代码是怎么运行的:
ba891976-5269-4f78-8222-5512e7b47c4d

  1. Hi there! Manager of the site here. Thanks for checking us out .

    您好!这里的网站经理。感谢检查我们 。不知道这是否有道理…我用谷歌翻译。

  2. Pingback: OpenStack Hacker养成指南 | UnitedStack Inc.

  3. Pingback: OpenStack Hacker养成指南 « OpenStack中国社区

    • 抱歉,最近在忙着装修房子,没有看到你的回复,你的回复是对的。我的编辑器不太好使,有时候会有意想不到的排版问题,当然也有我不够细心的原因。谢谢你的回复,我会马上改正的。

  4. Pingback: OpenStack Hacker养成指南 | 李立辉的技术与网络营销博客

  5. Pingback: dotoCloudComputing » OpenStack Hacker养成指南

  6. Pingback: OpenStack Hacker养成指南 | 新世纪Linux社区

  7. Pingback: OpenStack Hacker养成指南 | 扣扣家园

  8. Pingback: title loan