我应该直接使用 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
我听一个人说你不应该直接使用魔法方法。而且我认为在某些用例中我将不得不直接使用魔术方法。这么有经验的开发者,我应该直接使用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 toxxx.__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