Python __iter__ и для циклов - PullRequest
3 голосов
/ 14 марта 2011

Насколько я понимаю, я могу использовать конструкцию цикла for для объекта с методом __iter__, который возвращает итератор. У меня есть объект, для которого я реализую следующий метод __getattribute__:

def __getattribute__(self,name):
    if name in ["read","readlines","readline","seek","__iter__","closed","fileno","flush","mode","tell","truncate","write","writelines","xreadlines"]:
        return getattr(self.file,name)
    return object.__getattribute__(self,name)

У меня есть объект этого класса, a, для которого происходит следующее:

>>> hasattr(a,"__iter__")
True
>>> for l in a: print l
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'TmpFile' object is not iterable
>>> for l in a.file: print l
...
>>>

Итак, python видит, что a имеет метод __iter__, но не думает, что он повторяется. Что я сделал не так? Это с Python 2.6.4.

Ответы [ 2 ]

12 голосов
/ 14 марта 2011

На вашем пути есть тонкая деталь реализации: __iter__ на самом деле не метод экземпляра, а метод класса.То есть вызывается obj.__class__.__iter__(obj), а не obj.__iter__().

Это связано с оптимизацией слотов под капотом, позволяющей среде исполнения Python быстрее устанавливать итераторы.Это необходимо, поскольку очень важно, чтобы итераторы работали как можно быстрее.

Невозможно определить __getattribute__ для базового типа class, поэтому невозможно динамически возвращать этот метод.Это относится к большинству __metamethods__;вам нужно написать реальную оболочку.

4 голосов
/ 14 марта 2011

Некоторые из специальных методов оптимизируются при создании класса и не могут быть добавлены позже или переопределены присваиванием.См. документацию для __getattribute__, в которой говорится:

Этот метод все еще можно обойти при поиске специальных методов в результате неявного вызова через синтаксис языка или встроенные функции..

В этом случае вам необходимо предоставить прямую реализацию __iter__, которая перенаправляет вызов:

def __iter__(self):
    return self.file.__iter__()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...