2017-04-11 39 views
9

Gdybym zdefiniować metodę __iter__ następująco, to nie będzie działać:Dlaczego `__iter__` nie działa, gdy jest zdefiniowane jako zmienna instancji?

class A: 

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


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

iter(A()) 

Wynik:

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

Jak widać, wzywającą A().__iter__() działa, ale A() nie jest iterable.

Jednak gdybym określić __iter__ dla klasy, to będzie działać:

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 

Czy ktoś wie dlaczego pyton został zaprojektowany w taki sposób? tj. dlaczego __iter__ jako zmienna instancji nie działa? Nie uważasz, że to nieintuicyjne?

+0

Myślę, że sposób, w jaki próbujesz to zrobić w sposób bardzo niezrozumiały, dlaczego po prostu nie zastąpisz __iter__ jako metody? http://stackoverflow.com/questions/4019971/how-to-implement-iter-self-for-a-container-object-python – PyNico

+1

Wygląda na to, że jest klasą klasyczną w starym stylu lub w nowym stylu. Twój kod nie działa z klasami nowego stylu. – timgeb

+0

@PyNico W szczególnym przypadku, nad którym obecnie pracuję, wolę zdefiniować '__iter__' wewnątrz' __init__', ponieważ jego implementacja zależy od argumentów instancji. – AXO

Odpowiedz

5

Dokonuje się tego według projektu. Dokładny opis można znaleźć tutaj: https://docs.python.org/3/reference/datamodel.html#special-method-lookup

Krótka odpowiedź: specjalna metoda musi zostać ustawiona na samym obiekcie klasy, aby być konsekwentnie wywoływanym przez tłumacza.

Długa odpowiedź: ideą jest przyspieszenie znanych konstrukcji. W twoim przykładzie:

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

Jak często zamierzasz napisać taki kod w prawdziwym życiu? Tak więc, to, co robi Python - pomija wyszukiwanie słownika instancji, tj. iter(A()) po prostu nie "widzi" tego self.__iter__, które w tym przypadku jest faktycznie self.__dict__['__iter__'].

Pomija także wszystkie instancje __getattribute__ i wyszukiwanie metaklowy, uzyskując znaczące przyspieszenie.

+0

Przepisałem odpowiedź, aby była bardziej zrozumiała. Powiedz, jeśli masz jakieś pytania lub coś nie jest jasne. –

+0

Jest to prawdopodobnie również związane z tym, dlaczego '(1, 2, 3) [2]' jest o wiele szybsze niż bezpośrednie wywoływanie '(1, 2, 3) .__ getitem __ (2)' (w drugim pythonie również wygląda wewnątrz atrybuty instancji). Świetna odpowiedź, dziękuję bardzo. – AXO