类方法 静态方法和实例方法

参考:

关键词:对象 绑定

Python 类中的方法大致可以分为三种:

  • 类方法
  • 实例方法
  • 静态方法
class Foo(object):
    def test1(self):
        '''
        定义了实例方法
        '''
        print('instance {}'.format(self))

    @classmethod
    def test2(cls):
        '''
        定义了类方法
        '''
        print('class {}'.format(cls))

    @staticmethod
    def test3(n):
        '''
        定义了静态方法
        '''
        print('static n = {}'.format(n))

访问方式

  • 实例方法:通过实例和类进行访问,通过类访问需要手动绑定实例
s = Foo()
s.test1()
Foo.test1(s)
instance <__main__.Foo object at 0x00000236651661D0>
instance <__main__.Foo object at 0x00000236651661D0>
  • 类方法:通过类或者实例进行访问

因为通过实例可以反推得到类,所以可以进行访问

s = Foo()
Foo.test2()
s.test2()
class <class '__main__.Foo'>
class <class '__main__.Foo'>
  • 静态方法:通过类或者实例进行访问
s = Foo()
Foo.test3(5)
s.test3(5)
static n = 5
static n = 5

特性

  • 实例方法 需要绑定实例才能运行
>>> Foo.test1
<function __main__.Foo.test1>
>>> s = Foo()
>>> s.test1
<bound method Foo.test1 of <__main__.Foo object at 0x00000236651379B0>>

如果未绑定的方法 Foo.test1 不传实例对象给 self 时,就会报参数缺失错误,python2 要求第一个参数self是实例对象,而 python3 中可以是任意对象。

  • 类方法 无论通过类还是实例进行访问,都会自动绑定类
  • 静态方法 类里面的一个普通函数,与类和实例都没有绑定关系,只是存在于类中为类服务,静态方法如果作为全局函数也不会有什么问题。

典型应用场景

  • 类方法 作为工厂方法创建实例对象,例如内置模块 datetime.date 类中就有大量使用类方法作为工厂方法,以此来创建 date 对象。
class date:
    def __new__(cls, year, month=None, day=None):
        self = object.__new__(cls)
        self._year = year
        self._month = month
        self._day = day
        return self

    @classmethod
    def fromtimestamp(cls, t):
        y, m, d, * = _time.localtime(t)
        return cls(y, m, d)

    @classmethod
    def today(cls):
        t = _time.time()
        return cls.fromtimestamp(t)

如果需要在类中调用静态方法,最好把方法定义成类方法,因为要是定义成静态方法,那么就要显示地引用类 Foo,这对继承来说不是一件好事。

class Foo:

    @staticmethod
    def m1():
        pass

    @staticmethod
    def m2():
        A.m1() # bad

    @classmethod
    def m3(cls):
        cls.m1() # good
  • 静态方法 如果在方法中不需要访问任何实例方法和属性,纯粹地通过传入参数并返回数据,那么适合用静态方法,可以节省实例化对象的开销,通常这种方法放在类外面的模块层作为一个函数存在也是没问题的,而放在类中,仅为这个类服务。