带有@classmethod的披萨工厂

如果你在现实世界中接触过披萨,你就会知道有很多不同的美味:

Pizza(['mozzarella', 'tomatoes'])
Pizza(['mozzarella', 'tomatoes', 'ham', 'mushrooms'])
Pizza(['mozzarella'] * 4)

几个世纪前,意大利人就弄清了比萨饼的分类,所以这些不同口味的比萨饼都有自己的名字。我们最好利用这一点,为Pizza类的用户提供更好的接口,以便于创建他们所渴望的Pizza对象。

一个好用的、整洁的方法是使用类方法作为工厂函数来存放我们可以创建的不同类型的比萨饼:

class Pizza:
    def __init__(self, ingredients):
        self.ingredients = ingredients
    def __repr__(self):
        return f'Pizza({self.ingredients!r})'
    @classmethod
    def margherita(cls):
        return cls(['mozzarella', 'tomatoes'])
    @classmethod
    def prosciutto(cls):
        return cls(['mozzarella', 'tomatoes', 'ham'])

请注意看我是如何在margherita和prosciutto方法中使用cls参数,而不是直接调用Pizza类生成实例对象。

这是一个小窍门,你可以遵循“不要自我重复(DRY) ”的原则。如果我们决定在某个时候重命名这个类,我们就不必在所有的类方法中更新类名称。

现在python静态方法,能用这些方法做什么?让我们试试看:

>>> Pizza.margherita()
Pizza(['mozzarella', 'tomatoes'])
>>> Pizza.prosciutto()
Pizza(['mozzarella', 'tomatoes', 'ham'])

如你所见,我们可以使用工厂函数来创建新的Pizza对象,这些对象是按照我们希望的方式配置的。它们都在内部使用相同的__init__初始化方法python静态方法,并且仅仅提供了一个快捷方式来记住所有不同的成分。

查看类方法的这种用途的另一种途径是:它们允许为你的类定义替代性的初始化方法。

python静态方法和类方法使用场景_python静态方法_实例方法 静态方法

Python只允许每个类使用一个__init__方法。使用类方法,有可能根据需要添加尽可能多的替代性的初始化方法。这可以(在一定程度上)使类的接口自文档化,并简化它们的使用。

什么时候使用静态方法

在这里想出一个好的例子有点困难。但告诉你吧,我会继续把“比萨饼”抻得越来越薄…

我想到的是:

import math
class Pizza:
    def __init__(self, radius, ingredients):
        self.radius = radius
        self.ingredients = ingredients
    def __repr__(self):
        return (f'Pizza({self.radius!r}, '
                f'{self.ingredients!r})')
    def area(self):
        return self.circle_area(self.radius)
    @staticmethod
    def circle_area(r):
        return r ** 2 * math.pi

我在这里做了哪些更改?首先,我修改了初始化方法和__repr__方法, 以便接受另外一个关于半径的参数。

我还添加了一个area()实例方法来计算并返回比萨饼的面积(这对于@property也是一个很好的候选项 – 但是,这只是一个虚构的示例)。

我没有直接在area()中计算面积,而是使用众所周知的圆面积公式,将其分解为独立的circle_area()静态方法。

我们试试吧!

>>> p = Pizza(4, ['mozzarella', 'tomatoes'])
>>> p
Pizza(4, ['mozzarella', 'tomatoes'])
>>> p.area()
50.26548245743669
>>> Pizza.circle_area(4)
50.26548245743669

当然,这是一个有点简陋的例子,但是它可以帮助解释静态方法所带来的一些好处。

正如我们所了解到的,静态方法不能访问类或实例状态,因为它们不接受cls或self参数。这是一个很大的限制,但这也是一个很好的信号,表明一个特定的方法独立于它周围的一切。

在上面的例子中,circle_area()显然不能以任何方式修改类或类实例。(当然,你总是可以用全局变量来解决这个问题,但这不是重点。)

静态方法为什么有用呢?

将一个方法标记为静态方法,不仅意味着这个方法不会修改类或实例状态,而且这种强制性要求在执行Python程序时还会强化。

这样的技术允许你明确地对类的各个部分进行调用,从而自然地引导新的开发工作在规定的范围内展开。当然,挑战这些限制是很容易的。但在实践中,它们常常有助于避免与原始设计相反的意外修改。

换言之,使用静态方法和类方法是传达开发者意图的方法,同时又能充分执行这种意图,以避免由于疏忽而造成的大多数的错误和bug,因为这些bugs可能会破坏原有的设计。

如果不将静态方法滥用,而是应用得恰到好处,那么所编写的程序则具有良好的可维护性,并降低了其他开发者犯错误的可能性。

静态方法对编写测试代码也有用处。

因为 circle_area()方法完全独立于类的其他部分,所以测试起来容易得多。

在单元测试中测试这种方法之前,我们不必担心创建一个完整的实例,可以像测试常规函数一样不停地测试。同样,这使得以后的维护更加容易。

总结

希望对您有所帮助!点赞关注,谢谢大家~~

限时特惠:本站每日持续更新海量设计资源,一年会员只需29.9元,全站资源免费下载
站长微信:ziyuanshu688