如何正确地让 `next` 使用重写的实例方法 `__next__`?
How to properly get `next` to use use overridden instance method `__next__`?
考虑以下片段。
class A:
def __next__(self):
return 2
a = A()
print(next(a),a.__next__()) # prints "2,2" as expected
a.__next__ = lambda: 4
print(next(a),a.__next__()) # prints "2,4". I expected "4,4"
显然,属性 __next__
已通过补丁更新,但内置的 next
功能无法解决该问题。
说
的python 3 docs docs on the python datamodel
For instance, if a class defines a method named __getitem__()
, and x
is an instance of this class, then x[i]
is roughly equivalent to type(x).__getitem__(x, i)
.
据此,我想出了如下的 hack
class A:
def next_(self):
return 2
def __next__(self):
return self.next_()
a = A()
print(next(a),a.__next__()) # 2,2
a.next_ = lambda: 4
print(next(a),a.__next__()) # 4,4
该代码有效,但以通过另一种 next_
方法的另一层间接为代价。
我的问题是:猴子修补 __next__
实例方法的正确方法是什么? python 这种设计背后的基本原理是什么?
你不能。特殊方法 特殊 它们不能在实例级别被覆盖。时期。如果你想 "customize" 实例行为,正确的方法是简单地拥有一个正确的实现,而不是你在 运行 时间交换的虚假实现。 更改值而不是方法。
可以在下一节末尾的 The History of Python - Adding Support for User-defined Classes 中找到基本原理:
Special Methods
As briefly mentioned in the last section, one of my main goals was to
keep the implementation of classes simple. In most object oriented
languages, there are a variety of special operators and methods that
only apply to classes. For example, in C++, there is a special syntax
for defining constructors and destructors that is different than the
normal syntax used to define ordinary function and methods.
I really didn't want to introduce additional syntax to handle special
operations for objects. So instead, I handled this by simply mapping
special operators to a predefined set of "special method" names such
as __init__
and __del__
. By defining methods with these names, users
could supply code related to the construction and destruction of
objects.
I also used this technique to allow user classes to redefine the
behavior of Python's operators. As previously noted, Python is
implemented in C and uses tables of function pointers to implement
various capabilities of built-in objects (e.g., “get attribute”, “add”
and “call”). To allow these capabilities to be defined in user-defined
classes, I mapped the various function pointers to special method
names such as __getattr__
, __add__
, and __call__
. There is a direct
correspondence between these names and the tables of function pointers
one has to define when implementing new Python objects in C.
总结:C 中定义的类型具有包含指向特殊方法的指针的结构。 Guido 希望与 Python 中定义的类型保持一致,因此他们的特殊方法最终被用于 class 级别。
实施能否始终遵循查找顺序?是的...以 巨大 速度成本,因为现在即使是 C 代码也必须首先对实例执行字典查找以确保是否定义了特殊方法并调用那。鉴于经常调用特殊方法,尤其是对于内置类型,直接指向 class 中的函数是有意义的。 python方的行为正好与此一致。
Python在演艺界一直不光彩。您建议的实施会 运行 非常缓慢,尤其是 20 年前,当时它是在功能较弱的机器上设计的,当时 JIT 极为罕见且不太容易理解(与现在相比)。
考虑以下片段。
class A:
def __next__(self):
return 2
a = A()
print(next(a),a.__next__()) # prints "2,2" as expected
a.__next__ = lambda: 4
print(next(a),a.__next__()) # prints "2,4". I expected "4,4"
显然,属性 __next__
已通过补丁更新,但内置的 next
功能无法解决该问题。
说
的python 3 docs docs on the python datamodelFor instance, if a class defines a method named
__getitem__()
, andx
is an instance of this class, thenx[i]
is roughly equivalent totype(x).__getitem__(x, i)
.
据此,我想出了如下的 hack
class A:
def next_(self):
return 2
def __next__(self):
return self.next_()
a = A()
print(next(a),a.__next__()) # 2,2
a.next_ = lambda: 4
print(next(a),a.__next__()) # 4,4
该代码有效,但以通过另一种 next_
方法的另一层间接为代价。
我的问题是:猴子修补 __next__
实例方法的正确方法是什么? python 这种设计背后的基本原理是什么?
你不能。特殊方法 特殊 它们不能在实例级别被覆盖。时期。如果你想 "customize" 实例行为,正确的方法是简单地拥有一个正确的实现,而不是你在 运行 时间交换的虚假实现。 更改值而不是方法。
可以在下一节末尾的 The History of Python - Adding Support for User-defined Classes 中找到基本原理:
Special Methods
As briefly mentioned in the last section, one of my main goals was to keep the implementation of classes simple. In most object oriented languages, there are a variety of special operators and methods that only apply to classes. For example, in C++, there is a special syntax for defining constructors and destructors that is different than the normal syntax used to define ordinary function and methods.
I really didn't want to introduce additional syntax to handle special operations for objects. So instead, I handled this by simply mapping special operators to a predefined set of "special method" names such as
__init__
and__del__
. By defining methods with these names, users could supply code related to the construction and destruction of objects.I also used this technique to allow user classes to redefine the behavior of Python's operators. As previously noted, Python is implemented in C and uses tables of function pointers to implement various capabilities of built-in objects (e.g., “get attribute”, “add” and “call”). To allow these capabilities to be defined in user-defined classes, I mapped the various function pointers to special method names such as
__getattr__
,__add__
, and__call__
. There is a direct correspondence between these names and the tables of function pointers one has to define when implementing new Python objects in C.
总结:C 中定义的类型具有包含指向特殊方法的指针的结构。 Guido 希望与 Python 中定义的类型保持一致,因此他们的特殊方法最终被用于 class 级别。
实施能否始终遵循查找顺序?是的...以 巨大 速度成本,因为现在即使是 C 代码也必须首先对实例执行字典查找以确保是否定义了特殊方法并调用那。鉴于经常调用特殊方法,尤其是对于内置类型,直接指向 class 中的函数是有意义的。 python方的行为正好与此一致。
Python在演艺界一直不光彩。您建议的实施会 运行 非常缓慢,尤其是 20 年前,当时它是在功能较弱的机器上设计的,当时 JIT 极为罕见且不太容易理解(与现在相比)。