如何使用静态方法、类方法

Python中方法的运作
方法是作为类的属性(attribute)存储的函数,你可以以下面的方式声明和获取函数:

class Pizza(object):

… def init(self, size):

… self.size = size

… def get_size(self):

… return self.size

Pizza.get_size

这又指什么呢?很快我们就会知道,试着调用一下:

Pizza.get_size()

Traceback (most recent call last):

File “”, line 1, in

TypeError: unbound method get_size() must be called with Pizza instance as first argument (got nothing instead)
这里我们不能调用这个方法是因为它没有被绑定到任一 Pizza 的实例上。一个方法需要一个实例作为它第一个参数

Pizza.get_size(Pizza(42))

42
现在可以了!我们试用一个实例作为 get_size 方法的第一个参数调用了它,所以一切变得很美好。

但是你很快会同意,这并不是一个很漂亮的调用方法的方式;因为每次我们想调用这个方法都必须使用到类。并且,如果我们不知道对象是哪个类的实例,这种方式就不方便了。所以,Python 为我们准备的是,它将类 Pizza 的所有的方法绑定到此类的任何实例上。

这意味着类 Pizza 的任意实例的属性 get_size 是一个已绑定的方法:第一个参数是实例本身的方法。

Pizza(42).get_size

<bound method Pizza.get_size of <main.Pizza object at 0x10314b310>>

Pizza(42).get_size()

42

如我们预期,现在不需要提供任何参数给 get_size,因为它已经被绑定(bound),它的 self 参数是自动地设为 Pizza 类的实例。

下面是一个更好的证明:

m = Pizza(42).get_size

m

<bound method Pizza.get_size of <main.Pizza object at 0x10314b350>>

m()

42
因此,你甚至不要保存一个对 Pizza 对象的饮用。它的方法已经被绑定在对象上,所以这个方法已经足够。

但是如何知道已绑定的方法被绑定在哪个对象上?技巧如下:

m = Pizza(42).get_size

m.self

<main.Pizza object at 0x10314b390>

m == m.self.get_size

True

易见,我们仍然保存着一个对对象的引用,当需要知道时也可以找到。

在 Python3 中,归属于一个类的函数不再被看成未绑定方法(unbound method),但是作为一个简单的函数,如果要求可以绑定在对象上。所以,在 Python3 中原理是一样的,模型被简化了。

class Pizza(object):

… def init(self, size):

… self.size = size

… def get_size(self):

… return self.size

Pizza.get_size

<function Pizza.get_size at 0x7f307f984dd0>

静态方法
静态方法是一类特殊的方法。有时,我们需要写属于一个类的方法,但是不需要用到对象本身。例如:
class Pizza(object):

@staticmethod

def mix_ingredients(x, y):

    return x + y



def cook(self):

    return self.mix_ingredients(self.cheese, self.vegetables)
    这里,将方法 mix_ingredients 作为一个非静态的方法也可以 work,但是给它一个 self 的参数将没有任何作用。

这儿的 decorator@staticmethod 带来一些特别的东西:

Pizza().cook is Pizza().cook

False

Pizza().mix_ingredients is Pizza().mix_ingredients

True

Pizza().mix_ingredients is Pizza.mix_ingredients

True

Pizza()

<main.Pizza object at 0x10314b410>

Pizza()

<main.Pizza object at 0x10314b510>

Python 不需要对每个实例化的 Pizza 对象实例化一个绑定的方法。

绑定的方法同样是对象,创建它们需要付出代价。这里的静态方法避免了这样的情况:

降低了阅读代码的难度:看到 @staticmethod 便知道这个方法不依赖与对象本身的状态;允许我们在子类中重载mix_ingredients方法。如果我们使用在模块最顶层定义的函数 mix_ingredients,一个继承自 Pizza 的类若不重载 cook,可能不可以改变混合成份(mix_ingredients)的方式。
类方法
什么是类方法?类方法是绑定在类而非对象上的方法!

class Pizza(object):

… radius = 42

… @classmethod

… def get_radius(cls):

… return cls.radius

Pizza.get_radius

<bound method type.get_radius of <class ‘main.Pizza’>>

Pizza().get_radius

<bound method type.get_radius of <class ‘main.Pizza’>>

Pizza.get_radius is Pizza().get_radius

False

Pizza.get_radius()

42

不管你如何使用这个方法,它总会被绑定在其归属的类上,同时它第一个参数是类本身(记住:类同样是对象)

何时使用这种方法?类方法一般用于下面两种:

  1. 工厂方法,被用来创建一个类的实例,完成一些预处理工作。如果我们使用一个 @staticmethod 静态方法,我们可能需要在函数中硬编码 Pizza 类的名称,使得任何继承自 Pizza 类的类不能使用我们的工厂用作自己的目的。
    class Pizza(object):

    def init(self, ingredients):

     self.ingredients = ingredients
    

    @classmethod

    def from_fridge(cls, fridge):

     return cls(fridge.get_cheese() + fridge.get_vegetables())
     2. 静态方法调静态方法:如果你将一个静态方法分解为几个静态方法,你不需要硬编码类名但可以使用类方法。使用这种方式来声明我们的方法,Pizza这个名字不需要直接被引用,并且继承和方法重载将会完美运作。
    

    class Pizza(object):

def init(self, radius, height):

self.radius = radius

self.height = height

@staticmethod

def compute_circumference(radius):

return math.pi * (radius ** 2)

@classmethod

def compute_volume(cls, height, radius):

return height * cls.compute_circumference(radius)

def get_volume(self):

return self.compute_volume(self.height, self.radius)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值