为什么Python使用“魔法方法”?

112 投票
7 回答
32914 浏览
提问于 2025-04-15 21:43

我对Python中广泛使用的“魔法方法”感到有点惊讶。

举个例子,如果一个类想要声明它的实例有“长度”,它就需要实现一个叫做 __len__ 的方法。当你写 len(obj) 时,这个方法会被调用。那为什么不直接定义一个 len 方法,让它可以像对象的成员一样直接调用,比如 obj.len() 呢?


另见: 为什么Python代码使用len()函数而不是长度方法?

7 个回答

18

Python中有个词叫“魔法方法”,因为这些方法真的能为你的程序带来一些神奇的效果。使用Python的魔法方法最大的好处之一就是,它们能让对象像内置类型那样工作。这意味着你可以避免使用那些丑陋、不直观和不标准的方式来执行基本操作。

我们来看一个例子:

dict1 = {1 : "ABC"}
dict2 = {2 : "EFG"}

dict1 + dict2
Traceback (most recent call last):
  File "python", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'dict' and 'dict'

这个例子会报错,因为字典类型不支持加法。现在,我们来扩展字典类,添加“__add__”这个魔法方法:

class AddableDict(dict):

    def __add__(self, otherObj):
        self.update(otherObj)
        return AddableDict(self)


dict1 = AddableDict({1 : "ABC"})
dict2 = AddableDict({2 : "EFG"})

print (dict1 + dict2)

现在,它会输出以下内容。

{1: 'ABC', 2: 'EFG'}

通过添加这个方法,突然间就像发生了魔法一样,之前的错误就消失了。

希望这样能让你更清楚。如果想了解更多信息,可以参考:

Python魔法方法指南(Rafe Kettler,2012)

22

来自Python的哲学:

面对不确定的情况,不要轻易猜测。
应该有一种——最好只有一种——明显的方法来解决问题。

这就是为什么开发者在自定义方法时,可以自由选择不同的方法名称,比如 getLength()length()getlength()等等。Python要求严格的命名规则,这样大家就可以使用一个通用的函数 len()

所有对许多对象类型都常用的操作都放在了魔法方法里,比如 __nonzero____len____repr__。不过,这些方法大多数是可选的。

运算符重载也是通过魔法方法来实现的(例如 __le__),所以用它们来处理其他常见操作也是很合理的。

71

据我所知,len 在这方面是特别的,而且它的使用有历史原因。

这里有一句来自常见问题解答的引用:

为什么Python对某些功能使用方法(比如list.index()),而对其他功能使用函数(比如len(list))?

主要原因是历史原因。函数被用来处理那些对一组类型通用的操作,这些操作甚至可以用于没有任何方法的对象(比如元组)。而且,当你使用Python的函数特性(比如map()、apply()等)时,使用一个可以直接应用于各种对象的函数会更方便。

实际上,把len()、max()、min()实现为内置函数,写的代码比把它们作为每种类型的方法实现要少。虽然可以对个别情况进行争论,但这就是Python的一部分,现在要做这样的根本性改变已经太晚了。这些函数必须保留,以避免大规模的代码崩溃。

其他的“魔法方法”(在Python的说法中其实叫做特殊方法)是非常有意义的,类似的功能在其他语言中也存在。它们主要用于在使用特殊语法时被隐式调用的代码。

例如:

  • 重载运算符(在C++等语言中存在)
  • 构造函数/析构函数
  • 访问属性的钩子
  • 元编程的工具

等等……

撰写回答