2008-12-29 7 views
15

Więc napisałem proste drzewo binarne w Pythonie i natknąłem się na [...]Mylące [...] Lista w Pythonie: Co to jest?

Nie wierzę, że jest to związane z obiektem Ellipsis, ale wydaje się, że ma coś wspólnego z nieskończonością. (z powodu płytkiej kopii Pythona?). Źródłem tej pętli nieskończoności i dlatego nie zostanie rozszerzona podczas rozszerzania, gdy dostęp jest coś jestem całkowicie pokonać, jednak

>>> a 
[[[[[], [], 8, 3], [[], [], 3, 2], 6, 3], [], 1, 4], [[], [], -4, 2], 0, 0] 
>>> Keys(a)#With a+b 
[0, 1, 6, 8, 3, -4] 
>>> Keys(a)#With [a,b] 
[8, [...], [...], 3, [...], [...], 6, [...], [...], 1, [...], [...], -4, [...], [...], 0, [...], [...]] 
>>> Keys(a)[1]#?? 
[8, [...], [...], 3, [...], [...], 6, [...], [...], 1, [...], [...], -4, [...], [...], 0, [...], [...], 8, [...], [...], 3, [...], [...], 6, [...], [...], 1, [...], [...], -4, [...], [...], 0, [...], [...]] 

Wersja użyciu + b

def Keys(x,y=[]): 
    if len(x):y+=[x[2]]+Keys(x[0],y)+Keys(x[1],y)#Though it seems I was using y=y[:]+, this actually outputs an ugly mess 
    return y 

wersję przy użyciu [a , b]

def Keys(x,y=[]): 
    if len(x):y+=[x[2],Keys(x[0],y),Keys(x[1],y)] 
    return y 

Czym dokładnie jest [...]?

+0

Proszę być bardziej konkretny i rzeczowy. – andHapp

+1

Będziesz chciał to edytować. Myślę, że sedno pytania kręci się wokół obiektu Ellipsis, o którym trudno wiedzieć, jeśli jeszcze go nie widziałeś (i trudno znaleźć dokumenty, nawet jeśli wiesz o tym). –

+0

Obecna forma pytania nie ma żadnego sensu. Jeśli "a" jest (jak pokazano) listą list, to 'a' nie ma metody' keys() '. Napraw to pytanie, aby pokazać, co właściwie robisz. –

Odpowiedz

2

EDYCJA: Jak wspomniano powyżej, nie jest to obiekt Ellipsis, ale wynik zapętlonej listy. Podskoczyłem z pistoletu. Wiedza na temat obiektu Ellipsis to dobra wiedza na temat tylnej półki, jeśli znajdziesz Elipsa w jakimś prawdziwym kodzie, a nie na wyjściu.


Obiekt Ellipsis w języku Python służy do rozszerzonej notacji plastra. Nie jest on używany w obecnych bibliotekach Pythona, ale jest dostępny dla programistów do definiowania w ich własnych bibliotekach. Na przykład NumPy (lub SciPy) używają tego jako części swojego obiektu tablicy. Musisz przyjrzeć się dokumentacji drzewa(), aby dokładnie wiedzieć, jak zachowuje się Ellipsis w tym obiekcie.

Od Python documentation:

3.11.8 wielokropka Object

Ten przedmiot jest używany przez przedłużony plaster notacji (patrz Python Reference ręczny). Nie obsługuje żadnych specjalnych operacji . Istnieje dokładnie jeden obiekt wielokropka o nazwie Ellipsis (nazwa wbudowana ).

Został napisany jako Ellipsis.

23

Może również pojawić się, jeśli masz okrągłą strukturę z listą skierowaną do siebie. Tak:

>>> a = [1,2] 
>>> a.append(a) 
>>> a 
[1, 2, [...]] 
>>> 

Ponieważ Python nie można wydrukować strukturę (byłoby nieskończoną pętlę) używa wielokropka, aby pokazać, że nie ma rekurencji w strukturze.


Nie jestem do końca pewien, czy chodzi o to, co się dzieje i jak to naprawić, ale spróbuję poprawić powyższe funkcje.

W obu z nich najpierw dwa wywołania cykliczne, które dodają dane do listy y, a następnie PONOWNIE dołączają zwrócone dane do y. Oznacza to, że te same dane będą obecne kilka razy w wyniku.

Albo po prostu zebrać wszystkie dane bez dodawania do każdego y, z czymś

return [x[2]]+keys(x[0])+keys(x[1]) 

lub po prostu zrobić dołączanie w zaproszeniach, coś jak

y += [x[2]] 
keys(x[0], y) #Add left children to y... 
keys(x[1], y) #Add right children to y... 
return y 

(oczywiście, zarówno te fragmenty wymagają obsługi pustych list itp.)

@Abgan zauważyłem również, że naprawdę nie chcesz y=[] w inicjalizatorze .

5

Nie rozumiem twojego kodu powyżej, ale [...] myślę, że interpreter Pythona pomija nieskończone struktury danych. Na przykład:

>>> a = [0, 1] 
>>> a[0] = a 
>>> a 
[[...], 1] 

Wygląda na to, że twoja struktura drzewa zapętla się.

Odpowiedzi na temat obiektów plasterków znajdują się poza punktem.

6

Wierzę, że twoje "drzewo" zawiera się, dlatego zawiera cykle.

Spróbuj kod:

 
    a = [1,2,3,4] 
    print a 
    a.append(a) 
    print a 

Pierwsze wyjścia druku:

 
    [1,2,3,4] 

natomiast druga:

 
    [1,2,3,4, [...]] 

Powodem korzysta

 
def Keys(x,y=[]): 
To jest złe i zło. Lista jest obiektem zmiennym, a gdy jest używana jako parametr domyślny, jest zachowywana między wywołaniami funkcji. Więc każdy y + = „coś” operacja dodaje do tej samej listy (we wszystkich wywołań funkcji, a ponieważ funkcja jest rekurencyjna ...)


Zobacz Effbot lub Devshed więcej szczegółów dotyczących obiektów modyfikowalnych minęły jako wartości domyślne dla funkcji.

+0

Dodano y = y [:] na początek wersji [a, b] i otrzymałem wynik [[0], [[1], [[6], [[8], [], []] , [[3], [], []]], []], [[-4], [], []]] –

+0

Cóż, na moim miejscu jest 4:27, więc nie jestem do końca po nawiasach. Co jest nie tak z wyjściem? I naprawdę powinieneś używać "def Keys (x, y = None): jeśli y jest None: y = []" zamiast tego. – Abgan

4

nie wierzę to być związane z przedmiotem Ellipsis, bardziej wydaje się mieć coś wspólnego z pętli nieskończoności (ze względu na płytkiej kopii Pythona?). Źródłem tej pętli nieskończoności i dlatego nie zostanie rozszerzona podczas rozszerzania, gdy dostęp jest coś jestem całkowicie pokonać, jednak

Spójrz na poniższy kod:

>>> a = [0] 
>>> a.append(a) 
>>> print a 
[0, [...]] 

Jak Python ma wydrukować? Jest to lista zawierająca zero i odniesienie do niej samej.Stąd jest to lista, która zawiera zera i odniesienie do wykazu

[0, [...]] 

który z kolei zawiera zero i odniesienie do wykazu

[0, [0, [...]]] 

który z kolei zawiera zero i odniesienie do listy, i tak dalej, rekurencyjnie:

[0, [0, [0, [...]]]] 
[0, [0, [0, [0, [...]]]]] 
[0, [0, [0, [0, [0, [...]]]]]] 
... 

Nie ma nic złego w rekurencyjnego samej struktury danych. Jedyny problem polega na tym, że nie można go wyświetlać w postaci nieskończonej rekurencji. W związku z tym Python zatrzymuje się na pierwszym etapie rekursji i zajmuje się zagadnieniem nieskończoności, drukując tylko elipsę, jak wskazano w poprzednich odpowiedziach.

+0

Po wywołaniu [1] ponownie otrzymujesz [0, [...]]. W przypadku mojego przykładu wydaje się, że zwraca większą listę zamiast tej samej listy. Być może Python łączy [...] + [...] w [...]? –

+0

Po wywołaniu [1] ponownie otrzymujesz [0, [...]]: TAK, ponieważ [1] jest samą! –

1

Ok, więc w punktach:

  1. podczas tworzenia nieskończonej dane strukturę:

    def Keys(x,y=[])
    będzie korzystać z tego samego 'y' w każde wezwanie. To po prostu nie jest poprawne.

  2. Oświadczenie print jednak jest na tyle mądry, aby nie drukować nieskończonej danych, ale z okazji samoodnoszenie z [...] (znana jako Ellipsis)

  3. Python pozwolisz aby poprawnie adresować taką strukturę, abyś mógł napisać
    a.keys()[1][1][1]
    i tak dalej. Dlaczego nie powinieneś?
  4. Oświadczenie y = y[:] po prostu kopiuje listę y. Można to zrobić mocniej z y = list(y)

Spróbuj użyć następującego kodu:

 
def Keys(x,y=None): 
    if y is None: 
     y = [] 
    if len(x): 
     y += [x[2], Keys(x[0],y), Keys(x[1],y)] 
    return y 

Ale nadal myślę, że może cię ugryźć. Nadal używasz tej samej zmiennej Y (mam na myśli ten sam obiekt) w trzech miejscach w jednym wyrażeniu:

 y += [x[2], Keys(x[0], y), Keys(x[1], y)]

Czy to, co naprawdę chcesz osiągnąć? A może należy spróbować:

 
def mKeys(x,y=None): 
    if y is None: 
     y = [] 
    if len(x): 
     z = [x[2], mKeys(x[0], y), mKeys(x[1],y)] 
     return z 
    return [] 
1

Dla różnicy pomiędzy dwoma wersjami z klawiszy funkcyjnych, należy zwrócić uwagę na następujące różnice:

y+=[x[2]]+Keys(x[0],y)+Keys(x[1],y) 

Prawo wartość boczny w tym stwierdzeniu jest lista, która zawiera x [2], a także z elementów kluczy (x [0], y) i elementami kluczy (x [1], y)

y+=[x[2],Keys(x[0],y),Keys(x[1],y)] 

Właściwy stosunek boku w tej instrukcji jest lista, która zawiera x [2], plus klawisze LISTY (x [2], y) i klawisze LISTY (x [1], y).

Tak więc wersja z [a, b] spowoduje, że y zawiera się w swoich elementach.

Niektóre inne uwagi:

  1. Ponieważ w Pythonie, obiekt domyślnie jest tworzony raz, gdy funkcja jest zdefiniowana, pierwsza wersja nie będzie działać jak widać na powyższym przykładzie. Będzie zawierał wiele kopii niektórych kluczy. Trudno to wyjaśnić w skrócie, ale możesz wpaść na jakiś pomysł, drukując wartości x, y przy każdym wywołaniu klawiszy.

    Zostało to potwierdzone przez uruchomienie funkcji na moim komputerze za pomocą Pythona 2.5.2.

  2. Również dlatego, że wartość domyślna jest zdefiniowana tylko raz w czasie definiowania funkcji, nawet funkcja działa poprawnie po raz pierwszy, nie zadziała podczas wywoływania z innym a, ponieważ klucze w pierwszym drzewie binarnym pozostaną w y.

    Można to zobaczyć, dwukrotnie wywołując klawisze (a) lub wywołując je na dwóch różnych listach.

  3. Drugi parametr nie jest wymagany w przypadku tego problemu. Funkcja ta może być jak poniżej:

    def przycisków (A): jeżeli = []: powrotu [] innego: powrotu [A [2]] + kluczy ([0]) + kluczy (a [1])

    Definiowanie funkcji rekurencyjnej w zasadzie zawiera dwie części, rozwiązuje podproblemy i łączy wyniki. W twoim kodzie, łącząca część wyników jest powtarzana dwa razy: jeden przez gromadzenie ich w y, jeden przez dodanie listy razem.

+0

Dość elegancki. Chociaż musiałem zmienić [2] na [a [2]] –

3

Jeśli byś użył PrettyPrinter wyjście by było wymowne

>>> l = [1,2,3,4] 
>>> l[0]=l 
>>> l 
[[...], 2, 3, 4] 
>>> pp = pprint.PrettyPrinter(indent = 4) 
>>> pp.pprint(l) 
[<Recursion on list with id=70327632>, 2, 3, 4] 
>>> id(l) 
70327632 

Innymi słowy jej coś

enter image description here

0

problem jest, ponieważ jeden z element list odwołuje się do samej listy. Jeśli więc zostanie podjęta próba wydrukowania wszystkich elementów, to nigdy się nie skończy.

Ilustracja:

x = range(3) 
x.append(x) 
x[3][3][3][3][3][0] = 5 
print x 

wyjściowa:

[5, 1, 2, [...]] 

x[3] to odnosząc się do x sama. To samo dotyczy x[3][3].

To mogą być wizualizowane lepiej [tutaj] (http://pythontutor.com/visualize.html#code=x+%3D+range(3%29%0Ax.append(x%29%0Ax%5B3%5D%5B3%5D%5B3%5D%5B3%5D%5B3%5D%5B0%5D+%3D+5%0Aprint+x&mode=display&origin=opt-frontend.js&cumulative=false&heapPrimitives=false&textReferences=false&py=2&rawInputLstJSON=%5B%5D&curInstr=4)