我应该直接使用 python 魔术方法吗?

Should I use python magic methods directly?

我听一个人说你不应该直接使用魔法方法。而且我认为在某些用例中我将不得不直接使用魔术方法。这么有经验的开发者,我应该直接使用python魔术方法吗?

我不是高级开发人员,但我的经验表明你不应该直接调用魔法方法。

应该使用魔术方法来覆盖对象的行为。例如,如果你想定义你的对象是如何构建的,你可以覆盖 __init__。之后当你想初始化它时,你使用 MyNewObject() 而不是 MyNewObject.__init__()

对我来说,我倾向于欣赏 Alex Martelli 给出的答案 here:

When you see a call to the len built-in, you're sure that, if the program continues after that rather than raising an exception, the call has returned an integer, non-negative, and less than 2**31 -- when you see a call to xxx.__len__(), you have no certainty (except that the code's author is either unfamiliar with Python or up to no good;-).

如果你想了解更多关于Python的魔法方法,我强烈建议你看看Rafe Kettler制作的这个文档:https://rszalski.github.io/magicmethods/

不,你不应该。

可以用于 hackerrank 等快速代码问题,但不能用于生产代码。当我问这个问题时,我将它们用作第一个 class 函数。我的意思是,我用 xlen = x.__mod__ 而不是 xlen = lamda y: x % y 这样更方便。在简单的程序中使用这些片段是可以的,但在任何其他情况下都不行。

我打算展示直接使用魔术方法的一些好处:

1- 可读性:

使用像 len() 这样的内置函数比相关的 magic/special 方法 __len__() 更具可读性。想象一下只有魔术方法而不是内置函数的源代码......成千上万的下划线......


2-比较运算符:

class C:
    def __lt__(self, other):
        print('__lt__ called')

class D:
    pass

c = C()
d = D()

d > c
d.__gt__(c)

我还没有为这两个 class 实现 __gt__,但是在 d > c 中 python 看到 class D 没有 __gt__,它会检查 class C 是否实现了 __lt__。它确实如此,所以我们在输出中得到 '__lt__ called'd.__gt__(c) 不是这种情况。


3- 额外检查:

class C:
    def __len__(self):
        return 'boo'

obj = C()
print(obj.__len__())  # fine
print(len(obj))       # error

或:

class C:
    def __str__(self):
        return 10

obj = C()
print(obj.__str__())  # fine
print(str(obj))       # error

如您所见,当 python 隐式调用该魔术方法时,it does some extra checks 也会。


4- 这是最不重要的,但是与 __len__() 相比,对 str 等内置数据类型使用 len() 可以提高一点速度:

from timeit import timeit

string = 'abcdefghijklmn'

print(timeit("len(string)", globals=globals(), number=10_000_000))
print(timeit("string.__len__()", globals=globals(), number=10_000_000))

输出:

0.5442426
0.8312854999999999