Dlaczego listy python mają pop (), ale nie push ()

265

Czy ktoś wie, dlaczego list.appendfunkcja Pythona nie jest wywoływana, list.pushbiorąc pod uwagę, że istnieje już element, list.popktóry usuwa i zwraca ostatni element (indeksowany jako -1), a list.appendsemantyczny jest zgodny z tym zastosowaniem?

Eddie Welker
źródło
21
<nitpick> To metoda, a nie funkcja. </nitpick>
Tim Pietzcker
49
Myślę, że to świetne pytanie, choć może powinno być sformułowane: „Dlaczego listy python mają pop (), ale nie push ()”.
Uri
6
popmoże wyskakiwać z dowolnego miejsca na liście. appendnie można „wepchnąć” czegoś na środek listy.
endolith
@TimPietzcker <nitpick ^ 2> Metoda jest rzeczywiście funkcją, metoda (funkcja członka) jest podzbiorem funkcji :)
jave.web

Odpowiedzi:

246

Ponieważ „append” istniało na długo przed myśleniem o „pop”. Lista obsługiwana przez Python 0.9.1. Dołącza na początku 1991 roku. Dla porównania, oto część dyskusji na temat comp.lang.python na temat dodawania popu w 1997 roku. Guido napisał:

Aby zaimplementować stos, należałoby dodać operację podstawową list.pop () (i nie, nie jestem przeciwny temu konkretnemu na podstawie jakiejkolwiek zasady). List.push () można dodać dla symetrii z list.pop (), ale nie jestem wielkim fanem wielu nazw dla tej samej operacji - prędzej czy później będziesz czytał kod, który używa drugiej, więc musisz nauczyć się obu, co jest bardziej obciążeniem poznawczym.

Możesz także zobaczyć, jak omawia pomysł, czy push / pop / put / pull powinien znajdować się w elemencie [0] lub za elementem [-1], w którym zamieszcza odwołanie do listy ikon:

Nadal uważam, że najlepiej to wszystko pominąć w implementacji obiektu listy - jeśli potrzebujesz stosu lub kolejki ze szczególną semantyką, napisz małą klasę, która używa list

Innymi słowy, dla stosów zaimplementowanych bezpośrednio jako listy Python, które już obsługują szybkie append () i del list [-1], sensowne jest, aby list.pop () domyślnie działał na ostatnim elemencie. Nawet jeśli inne języki robią to inaczej.

Domniemane jest to, że większość ludzi musi dołączyć się do listy, ale o wiele mniej ma okazję traktować listy jako stosy, dlatego lista list.append pojawiła się znacznie wcześniej.

Andrew Dalke
źródło
16
@poige you're going to *read* code that uses the other one (...) which is more cognitive loadPamiętaj, że „nie ma push” wprowadza ładunek poznawczy tylko podczas pisania kodu. Pamiętanie, że „push jest dokładnym synonimem append”, wprowadza ładunek poznawczy, ilekroć czytasz ten, którego używasz rzadziej. Zobacz stackoverflow.com/questions/3455488/…, aby dowiedzieć się więcej o tym, dlaczego ludzie myślą, że czytelność często przebija zdolność do zapisu
stevenjackson121
2
Nie ma żadnego usprawiedliwienia / sensu
poige
15

Ponieważ dołącza się; nie pcha. „Dołączanie” dodaje na końcu listy, „pchanie” dodaje na początku.

Pomyśl o kolejce kontra stosie.

http://docs.python.org/tutorial/datastructures.html

Edycja: Aby dokładnie przeredagować moje drugie zdanie, „Dołączanie” bardzo wyraźnie oznacza dodanie czegoś na końcu listy, niezależnie od podstawowej implementacji. To, gdzie nowy element zostanie dodany, gdy zostanie „wypchnięty”, jest mniej jasne. Wciśnięcie na stos oznacza umieszczenie czegoś na „górze”, ale to, gdzie faktycznie idzie w podstawowej strukturze danych, zależy całkowicie od implementacji. Z drugiej strony, wypychanie do kolejki oznacza dodawanie jej do końca.

Matt Ball
źródło
4
Samouczek wydaje się sugerować, że po prostu popycha i wyskakuje od końca: „Metody list bardzo ułatwiają używanie listy jako stosu, w którym ostatni dodany element jest pierwszym pobieranym elementem („ ostatni na wejściu, pierwszy na wyjściu ” ”). Aby dodać element na górę stosu, użyj append (). Aby pobrać element ze szczytu stosu, użyj pop () bez wyraźnego indeksu.”
Uri
110
„pchanie” w żaden sposób nie oznacza dodawania z przodu. każda implementacja stosu, która kiedykolwiek została napisana przez zdrową osobę „wypycha” na górę (koniec) stosu, a nie na dół (początek) stosu
Kip
4
korekta: każda * implementacja tablicowa . wdrożenie listy połączonej zepchnęłoby do głowy.
Kip
16
javascript pushdodaje do końca.
Kobi
2
Nie, biorąc pod uwagę list.popsemantykę, list.appendwypycha elementy do listy, gdy jest postrzegane jako stos.
fortran
10

Ponieważ dołącza element do listy? Push odnosi się zwykle do stosów.

JesperE
źródło
7
Listą może być jednak stos. :-)
Jason Baker
@JasonBaker Możesz zaimplementować stos za pomocą listy, ale to nie znaczy, że stos list ==. Możesz także zaimplementować stos za pomocą kolejki, jeśli naprawdę tego potrzebujesz. (Byłoby to okropnie nieefektywne, ale jest możliwe!)
Mark E. Haase
Zamieszanie naprawdę wynika z faktu, że stos nie ma „początku” ani „końca” jak lista, ale raczej „górę” i „dół”. Dodanie do stosu oznacza umieszczenie elementu na górze i „pchanie” w dół. „Pchanie” z przodu nie ma sensu (przynajmniej nie pod względem językowym). Aby jeszcze bardziej skomplikować sytuację, C ++ używa „push_front” i „push_back”.
JesperE
9

Ponieważ „dołącz” intuicyjnie oznacza „dodaj na końcu listy”. Gdyby nazywało się to „push”, nie byłoby jasne, czy dodajemy rzeczy na końcu czy na początku listy.

Gyom
źródło
12
To nie ma sensu, ponieważ istnieje popoperacja. Ponieważ pushi popsą zwykle operacjami stosowymi i idą w parze, należy oczekiwać, że działają one na tym samym końcu listy.
jamesdlin,
7

Nie jest to oficjalna odpowiedź w żaden sposób (tylko zgadywanie oparte na użyciu języka), ale Python pozwala używać list jako stosów (np. Sekcja 5.1.1 samouczka ). Jednak lista wciąż jest przede wszystkim listą, więc operacje, które są wspólne dla obu, używają terminów listowych (tj. Dołączaj), a nie stosów (tj. Push). Ponieważ operacja pop nie jest tak powszechna na listach (chociaż można było użyć „removeLast”), zdefiniowano pop (), ale nie push ().

Uri
źródło
3

Ok, osobista opinia tutaj, ale Append and Prepend implikują precyzyjne pozycje w zestawie.

Push i Pop to tak naprawdę koncepcje, które można zastosować na każdym końcu zestawu ... Tak długo, jak jesteś konsekwentny ... Z jakiegoś powodu Push () wydaje się, że powinien mieć zastosowanie do przedniej części zestaw...

dicroce
źródło
3
Skoro już o tym wspomniałeś, jeśli tablice mają funkcję .append (), to dlaczego nie ma odpowiadającej im funkcji .prepend ()? Mogę nauczyć się używać .insert (0, val) do dodawania, ale wstydzę się braku odpowiedniej funkcji .delete (pos, val). ref: docs.python.org/2/library/array.html
MarkHu,
3

Do twojej wiadomości, nie jest strasznie trudne stworzenie listy, która ma metodę push:

>>> class StackList(list):
...     def push(self, item):
...             self.append(item)
... 
>>> x = StackList([1,2,3])
>>> x
[1, 2, 3]
>>> x.push(4)
>>> x
[1, 2, 3, 4]

Stos jest nieco abstrakcyjnym typem danych. Idea „wypychania” i „poppingu” jest w dużej mierze niezależna od tego, w jaki sposób stos jest faktycznie wdrażany. Na przykład możesz teoretycznie zaimplementować taki stos (chociaż nie wiem dlaczego):

l = [1,2,3]
l.insert(0, 1)
l.pop(0)

... i nie wdałem się w używanie połączonych list do implementowania stosu.

Jason Baker
źródło
1

Push jest zdefiniowanym zachowaniem stosu ; jeśli wepchniesz A na stos (B, C, D), dostaniesz (A, B, C, D).

Jeśli użyjesz Append Pythona, wynikowy zestaw danych będzie wyglądał następująco (B, C, D, A)

Edycja: Wow, święta pedanteria.

Zakładam, że z mojego przykładu jasno wynika, która część listy jest na górze, a która na dole. Zakładając, że większość z nas tutaj czyta od lewej do prawej, pierwszy element każdej listy zawsze będzie po lewej stronie.

Satanicpuppy
źródło
1
To nie prawda, pop usuwa z końca listy, a nie z przodu.
fortran
4
przeczytaj stronę, do której linkujesz. push jest definiowane jako pchanie na wierzch stosu. który koniec jest „górą”, zależy od implementacji. w stosie opartym na tablicy, push wypychałby na koniec tablicy. w stosie opartym na listach połączonych push wypychałby na początek.
Kip
0

Prawdopodobnie dlatego, że oryginalna wersja Pythona ( C Python) została napisana w C, a nie w C ++.

Pomysł, że lista jest tworzona przez wypychanie rzeczy na tył czegoś, prawdopodobnie nie jest tak dobrze znany, jak myśl o ich dodaniu.

rozwijać
źródło
Druga część to dobra odpowiedź. Ale co to ma wspólnego z implementacją w C / C ++?
Jason Baker
@Jason: W STL C ++ push_back () to sposób dołączania do listy. Próbowałem przekazać meta-pomysł, że pomysł, że listy są tworzone przez wypychanie, jest bardziej prawdopodobne, że pojawi się, jeśli pracujesz w C ++. Mieć sens?
zrelaksuj się
Jeśli masz typ listy zaimplementowany jako ciągła tablica (wektor w C ++, lista w Pythonie, tablica w Perlu), wówczas sensowne jest, aby „push” umieścił nowy element na końcu. Zauważysz, że perl 4 powinien „wypychać” i „pop” jako funkcje na tablicach dokładnie tak, jak Python append / pop i C ++ push_back / pop_back, i na długo przed tym, zanim STL został formalnie zaproponowany do C ++. Nie ma to więc nic wspólnego z tym, że STL C ++ tworzy nowe rozumienie rzeczy.
Andrew Dalke
Jedną z rzeczy, za którymi tęsknię za nauką języka Python na tle Perla, jest możliwość korzystania z wbudowanych operacji push (), pop (), shift () i unshift () w celu dodawania / usuwania elementów do / z dowolnego końca tego samego tablica . Mimo że mogę z łatwością zawinąć listę Pythona w klasę „Stackish” lub „Queueish”, nie wydaje się to tak łatwe (ani wydajne), aby wykonywać oba te zadania jednocześnie.
Peter
-2

Push i Pop mają sens pod względem metafory stosu talerzy lub tacek w stołówce lub bufecie, szczególnie tych w rodzaju uchwytu, który ma sprężynę pod spodem, więc górna płyta jest (mniej więcej ... teoretycznie) w tym samym miejscu, bez względu na to, ile talerzy jest pod nim.

Jeśli wyjmiesz tacę, ciężar sprężyny będzie nieco mniejszy, a stos nieco „wyskoczy”, a jeśli odłożysz płytkę, „popchnie” stos w dół. Więc jeśli myślisz o liście jako o stosie, a ostatni element o tym, że jest na górze, nie powinieneś mieć większego zamieszania.

pion
źródło