2010-04-16 14 views
6

Próbuję napisać prosty interfejs użytkownika dla Plurk przy użyciu pyplurk.Nie mogę powtórzyć klasy listy w Pythonie

Udało mi się utworzyć połączenie API, zalogować się, pobrać i wyświetlić listę znajomych. Teraz próbuję pobrać i wyświetlić listę Plurków.

pyplurk zapewnia funkcję GetNewPlurks następująco:

def GetNewPlurks(self, since): 
    '''Get new plurks since the specified time. 
    Args: 
     since: [datetime.datetime] the timestamp criterion. 
    Returns: 
     A PlurkPostList object or None. 
    ''' 
    offset = jsonizer.conv_datetime(since) 
    status_code, result = self._CallAPI('/Polling/getPlurks', offset=offset) 
    return None if status_code != 200 else \ 
      PlurkPostList(result['plurks'], result['plurk_users'].values()) 

Jak widać ta zwraca PlurkPostList, który z kolei jest zdefiniowana w następujący sposób:

class PlurkPostList: 
    '''A list of plurks and the set of users that posted them.''' 
    def __init__(self, plurk_json_list, user_json_list=[]): 
    self._plurks = [PlurkPost(p) for p in plurk_json_list] 
    self._users = [PlurkUser(u) for u in user_json_list] 
    def __iter__(self): 
    return self._plurks 
    def GetUsers(self): 
    return self._users 
    def __eq__(self, other): 
    if other.__class__ != PlurkPostList: return False 
    if self._plurks != other._plurks: return False 
    if self._users != other._users: return False 
    return True 

Teraz oczekiwać, aby móc zrób coś takiego:

api = plurk_api_urllib2.PlurkAPI(open('api.key').read().strip(), debug_level=1) 
plurkproxy = PlurkProxy(api, json.loads) 
user = plurkproxy.Login('my_user', 'my_pass') 
ps = plurkproxy.GetNewPlurks(datetime.datetime(2009, 12, 12, 0, 0, 0)) 
print ps 
for p in ps: 
    print str(p) 

Kiedy to uruchomię, otrzymam:

<plurk.PlurkPostList instance at 0x01E8D738> 

z "druku PS", a następnie:

for p in ps: 
TypeError: __iter__ returned non-iterator of type 'list' 

nie rozumiem - na pewno listy jest iterable? Gdzie się mylę - w jaki sposób mogę uzyskać dostęp do Plurków w PlurkPostList?

+0

Niezwiązany z problemem, który masz, zawsze dziedziczę "obiekt", a nie nic (tj. 'Klasa PlurkPostList (object):'), więc używam * klas nowego stylu *. –

+0

... a jeśli uczynisz 'PlurkPostList' dziedziczącym ze standardowej' listy', masz znacznie mniej pracy do wykonania. – bobince

+0

@bobince, Niezupełnie. Lista dziedziczenia nie zapewnia niczego wartego. –

Odpowiedz

14

Podczas definiowania własną metodę __iter__, należy zdać sobie sprawę, że ta metoda __iter__ należy zwrócić iterator, a nie iterable. Zwracasz listę, a nie iterator do listy, więc zawiedzie. Możesz to naprawić, robiąc np. return iter(self._plurks).

Jeśli chciał zrobić coś bardziej skomplikowanego, jak każdy element procesu w self._plurks jak to jest powtórzyć skończy, zwykle Sztuką jest, aby metoda __iter__ być generator. Ten sposób, returnvalue o wywołaniu __iter__ to generator, który jest iteracyjnej:

def __iter__(self): 
    for item in self._plurks: 
     yield process(item) 
+1

Dziękuję, to działa idealnie.Definicja klasy PlurkPostList, w tym funkcja __iter__, pochodzi bezpośrednio od PyPlurk, więc beztrosko założyłem, że jest w porządku, a moje własne wywoływanie było niewystarczające. Nie przeniosłem się również do rozróżnienia między interweniarką a iteracją, więc było to bardzo przydatne. Dzięki. – Vicky

5

Sposób __iter__ należy zwrócić przedmiot, który realizuje sposób next().

Lista nie ma metody next(), ale ma metodę __iter__, która zwraca obiekt listiterator. Obiekt listiterator ma metodę next().

Należy napisać:

def __iter__(self): 
    return iter(self._plurks) 
0

Jako alternatywę można również zdefiniować funkcję next() i mają __iter__() powrotny siebie. Najlepszym przykładem jest Build a Basic Python Iterator.

+1

Powoduje to, że wiele iteracji tego samego obiektu jest uciążliwe. –

+0

Jak to by było uciążliwe? Czy czegoś brakuje? Miałem wrażenie, że używanie generatorów, tak jak ty, osiągnęło to samo, co użycie next(). Proszę popraw mnie jeżeli się mylę. – Jon

+1

Gdy sam obiekt jest iteratorem, musiałby zachować stan iteracji. Musiałby pamiętać, jak często nazywano metodę "następną". Kiedy używasz generatora, generator robi to za Ciebie. Po zaimplementowaniu iteratora należy go przechowywać gdzieś w iteratorze. Gdy obiekt jest jego własnym iteratorem (jak na przykład "plik"), to obiekt może być iterowany tylko raz, a następnie musi być przewinięty (w przypadku 'pliku', metodą' seek' lub przez ponowne otwarcie.) –

Powiązane problemy