【问题标题】:Why `__iter__` does not work when defined as an instance variable?为什么`__iter__`在定义为实例变量时不起作用?
【发布时间】:2017-09-06 21:06:26
【问题描述】:

如果我将__iter__方法定义如下,它将不起作用:

class A:

    def __init__(self):
        self.__iter__ = lambda: iter('text')


for i in A().__iter__():
    print(i)

iter(A())

结果:

t
e
x
t
Traceback (most recent call last):
  File "...\mytest.py", line 10, in <module>
    iter(A())
TypeError: 'A' object is not iterable

如您所见,调用A().__iter__() 有效,但A() 不可迭代。

但是,如果我为该类定义 __iter__,那么它将起作用:

class A:

    def __init__(self):

        self.__class__.__iter__ = staticmethod(lambda: iter('text'))
        # or:
        # self.__class__.__iter__ = lambda s: iter('text')


for i in A():
    print(i)

iter(A())

# will print:
# t
# e
# x
# t

有谁知道为什么 python 是这样设计的?即为什么 __iter__ 作为实例变量不起作用?你不觉得它不直观吗?

【问题讨论】:

  • 我认为您尝试这样做的方式非常不直观,为什么不直接将 iter 重写为方法? stackoverflow.com/questions/4019971/…
  • 似乎是旧式与新式类的问题。您的代码不适用于新式类。
  • @PyNico 在我目前正在处理的特定情况下,我更喜欢在__init__ 中定义__iter__,因为它的实现取决于实例化参数。

标签: python iteration iterable


【解决方案1】:

这是按设计完成的。你可以在这里找到详细的描述:https://docs.python.org/3/reference/datamodel.html#special-method-lookup

简短的回答:必须在类对象本身上设置特殊方法,以便解释器始终如一地调用。

长答案:这背后的想法是加快众所周知的建设。在你的例子中:

class A:
    def __init__(self):
        self.__iter__ = lambda: iter('text')

在现实生活中,您多久会编写一次这样的代码?所以,Python 做了什么——它跳过了实例的字典查找,即iter(A()) 根本没有“看到”self.__iter__,在这种情况下实际上是self.__dict__['__iter__']

它还跳过了所有 __getattribute__ 实例和元类查找,获得了显着的加速。

【讨论】:

  • 我重写了答案以使其更易于理解。如果您有任何问题或不清楚的地方,请告诉我们。
  • 这可能也与为什么(1, 2, 3)[2] 比直接调用(1, 2, 3).__getitem__(2) 快得多有关(在后者中,python 还查看实例属性)。很好的答案,非常感谢。
猜你喜欢
  • 1970-01-01
  • 2013-11-02
  • 1970-01-01
  • 2021-06-26
  • 2016-05-27
  • 2014-12-09
  • 2010-12-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多