2011-03-14 1 views
3

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

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 
... 
>>> 

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

ответ

12

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

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

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

+1

+1 Так вот почему 'iter' не называют' __getattribute__' ... как говорится, вы каждый день узнаете что-то новое на SO :) – delnan

+0

+1 и что говорит дельнан. – slezica

+0

Обратите внимание, что вы можете видеть побочный эффект этого (по крайней мере, в CPython): если вы определяете '__getattribute__', вы заметите, что он вызывается для' __class__', когда вы используете 'iter', поскольку среда выполнения просматривает класс объекта для вызова '__iter__'. (Это, вероятно, следует рассматривать как деталь реализации). –

4

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

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

Что вам нужно сделать в этом случае обеспечить непосредственное осуществление __iter__, которая перенаправляет вызов:

def __iter__(self): 
    return self.file.__iter__()