python学习系列---staticmethod和classmethod

本文详细探讨了Python中的staticmethod和classmethod,通过实例解析它们的使用场景和区别。文章介绍了实例方法、静态方法和类方法的基本概念,并通过鸭子测试阐述了归纳推理的重要性。在应用举例部分,展示了如何在派生类中使用静态方法和类方法,以及它们在工厂方法和组织代码结构中的作用。最后强调了使用staticmethod和classmethod在减少实例化成本、代码隔离和命名空间整洁方面的好处。
摘要由CSDN通过智能技术生成


1. 在python类中有两个装饰器,staticmethod和classmethod, 它们的作用似乎明确又模糊。由于缺乏使用场景,我们对这两个装饰器(功能)的理解总是不够深入,不够全面。本文试图对它们进行一次全方位的考查,进而对它们的使用有一些更好的体会。

本人水平比较渣,以上良好的愿望应该只能是个愿望,这篇文章有很多不完善的地方,请各位读者不吝指出。


2. 鸭子测试(Duck Test)是对一种归纳推理方式的幽默的说法,它可以解释为:

如果它看起像鸭子,叫起来像鸭子,游起来像鸭子,那么它可能就是鸭子。

这个测试表明人能够通过观察未知事物的明显外在特征来推断该事物的本质。有时被用来解决看似深奥但其实并不深奥的问题。

很多时候,我们知道有一个事物,我们知道它的的名字,知道它出现在一些场合,但是我们并不明白它到底是怎么回事。这往往是由于我们对它的特征不清楚。通过观察这个事物的行为特征,或许我们就能逐渐了解它。


3. 实例方法。通常,在python类中定义的普通方法就是实例方法。它的语法如下:

class C(object):
    def f(self, arg1, arg2, ...):
        ...
实例方法的参数中有一个必不可少的参数self,它必须位于参数列表的第一个位置,它相当于该方法所属的类在实例化后的实例本身(Instance),表示传入该方法所属类的一个实例(Python2中必须是该类的实例,Python3中可以是任何东西)。实例方法被调用时,参数self被隐式地传入方法中,无需显式指定。

既然叫做实例方法,那么它必须使用该类的实例才能调用( C().f() ),直接使用类来调用该方法是无效的( C.f() )。


4. staticmethod(静态方法),需要一个装饰器语法(@staticmethod)将一个普通方法(实例方法)转换为静态方法:

class C(object):
    @staticmethod
    def f(arg1, arg2, ...):
        ...
staticmethod 方法的参数是自定义的任何参数,当然也可以没有参数。它不需要一个隐含参数,像self这样的。这是它与实例方法和类方法之间在形式上的一个主要不同之处。

staticmethod即可以在类上调用(C.f())也可以在实例上调用(C().f()). 在实例上调用时,实例被忽略而类被使用---实际上还是类调用。

staticmethod不需要自身对象self和自身类的cls参数,没有对类或实例的依赖,它处理与类无关的信息,就像恰好放在类中的一个局部函数,但是它的功能又与类有某种关联。

如果需要在staticmethod中调用类的属性和方法,可以直接用类名.属性名/类名.方法名。


5. classmethod(类方法),需要一个装饰器语法(@classmethod)将一个普通方法(实例方法)转换为类方法:

class C(object):
    @classmethod
    def f(cls, arg1, arg2, ...):
        ...
classmethod需要接收一个隐含参数作为第一个参数,不同于实例方法的self, 类方法的隐含参数叫做cls(其实可以叫任何别的名字,这里主要是因为命名惯例), 表示传入该方法所属的类。 

classmethod即可以在类上调用(C.f())也可以在实例上调用(C().f()). 在实例上调用时,实例被忽略而类被使用---实际上还是类调用。

如果classmethod是在派生类中被调用的,被隐式传入cls参数的是那个子类对象,而不是父类。


6. 应用举例。下面通过代码列举了staticmethod和classmethod的一些使用场合。

  6.1 基本使用。定义一个实例方法,静态方法和类方法,并分别进行调用。

class A(object):
    def im(self):
        print 'Instance method: ', self
    @classmethod
    def cm(cls):
        print 'Class method: ', cls
        return cls
    @staticmethod
    def sm():
        print 'Static method.'
  调用过程如下:

>>> A().im()		在实例上调用实例方法
Instance method:  <A.A object at 0x7f95dfb19210>
>>> A().sm() 		在实例上调用静态方法
Static method.
>>> A().cm() 		在实例上调用类方法
Class method:  <class 'A.A'>
>>> A.im() 		在类上调用实例方法,出错  
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method im() must be called with A instance as first argument (got nothing instead)
>>> A.sm() 		在类上调用静态方法
Static method.
>>> A.cm() 		在类上调用类方法
Class method:  <class 'A.A'>


  6.2  在派生类中使用父类的类方法。

class B(A):
	pass 

调用如下:  

>>> B.cm() 在子类中调用父类的类方法

Class method:  <class '__main__.B'> 显示的cls参数值为子类对象


6.3 将类方法用于工厂方法。这时 classmethod 的作用实际上是创建了类的实例, 而在这之前可以做一些预处理,比如设置变量信息。在下面的例子中,如果使用 @staticmethod代替,那我们不得不硬编码Pizza类名在函数中,这使得任何继承Pizza的类都不能使用我们这个工厂方法给它自己用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值