Python __iter__ et pour les boucles
Question
Si je comprends bien, je peux utiliser la construction de la boucle de for
sur un objet avec une méthode de __iter__
qui retourne un itérateur. Je un objet pour lequel je mettre en œuvre le procédé de __getattribute__
de suivant:
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)
J'ai un objet de cette classe, a
pour laquelle les éléments suivants se produit:
>>> 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 Ainsi voit que a
a une méthode de __iter__
, mais ne pense pas que ce soit itérables. Qu'est ce que j'ai mal fait? C'est avec python 2.6.4.
La solution
Il y a un détail de mise en œuvre subtile obtenir de votre manière: __iter__
n'est pas réellement une méthode d'instance, mais une méthode de classe. Autrement dit, obj.__class__.__iter__(obj)
est appelé, plutôt que obj.__iter__()
.
Ceci est dû à des optimisations de machines à sous sous le capot, ce qui permet l'exécution Python de mettre en place plus rapidement itérateurs. Cela est nécessaire car il est très important que itérateurs être aussi rapide que possible.
Il est impossible de définir __getattribute__
pour le type de class
sous-jacente, il est donc impossible de retourner cette méthode dynamique. Cela vaut pour la plupart __metamethods__
; vous aurez besoin d'écrire une enveloppe réelle.
Autres conseils
Certaines des méthodes spéciales sont optimisées quand une classe est créée et ne peut être ajouté ultérieurement ou annulé par la cession. Consultez la documentation pour __getattribute__
qui dit:
Cette méthode peut encore être contournée lorsque à la recherche des méthodes spéciales comme la résultat d'invocation implicite par syntaxe du langage ou des fonctions intégrées.
Ce que vous devez faire dans ce cas fournir une mise en œuvre directe de __iter__
qui transmet l'appel:
def __iter__(self):
return self.file.__iter__()