Kiedy używać słownika vs krotki w Pythonie


31

Konkretnym przykładem jest lista nazw plików i ich rozmiarów. Nie mogę zdecydować, czy każdy element na liście powinien mieć formę {"filename": "blabla", "size": 123}, czy tylko ("blabla", 123). Słownik wydaje mi się bardziej logiczny, ponieważ na przykład dostęp do rozmiaru file["size"]jest bardziej objaśniający niż file[1]... ale tak naprawdę nie jestem pewien. Myśli?


Jako uzupełnienie, rozważ rozpakowanie krotki , jeśli martwisz się o czytelność krotek - fname, file_size = filegdzie dane są twoim krotkiem, zlikwiduj je file[1]i zastąp je file_size. Oczywiście zależy to od dobrej dokumentacji.
nlsdfnbch

2
To zależy, jaką strukturę danych budujesz i jak zamierzasz uzyskać do niej dostęp? (według nazwy pliku? według indeksu? oba?) Czy jest to po prostu zmienna struktura danych / struktura, czy może dodasz inne elementy (/ atrybuty) oraz rozmiar? Czy struktura musi pamiętać zamówienie; czy chcesz posortować listę rozmiarów, czy uzyskać do niej dostęp według pozycji (np. „top-n największych / najmniejszych plików”)? W zależności od nich „najlepszą” odpowiedzią może być dict, OrdersDict, namedtuple, zwykła stara lista lub własna klasa niestandardowa. Potrzebujesz więcej kontekstu od ciebie.
smci

Odpowiedzi:


78

Użyłbym namedtuple:

from collections import namedtuple
Filesize = namedtuple('Filesize', 'filename size')
file = Filesize(filename="blabla", size=123)

Teraz można korzystać file.sizeoraz file.filenamew programie, który jest IMHO najbardziej czytelna forma. Uwaga namedtupletworzy niezmienne obiekty, takie jak krotki, i są one bardziej lekkie niż słowniki, jak opisano tutaj .


1
Dzięki, dobry pomysł, nigdy wcześniej o nich nie słyszałem (jestem dość nowicjuszem w Python). Pytanie: co się stanie, jeśli ktoś gdzie indziej w kodzie zdefiniuje tę samą „klasę”, być może nieco inaczej. np. w jakimś innym pliku źródłowym miał współpracownik BobFilesize = namedtuple('Filesize', 'filepath kilobytes')
user949300,

Możesz także użyć bardzo ładnego attrsmodułu (można go znaleźć piplub po prostu go wyszukać), który pozwala na uzyskanie bardzo podobnych udogodnień syntaktycznych do nazwanej krotki, ale może dać ci zmienność (ale może być również niezmienny). Główną różnicą funkcjonalną jest to, że attrsklasy stworzone nie są równe krotkom zwykłym, jak namedtupleto robią.
mtraceur,

3
@DocBrown Python nie ma pojęcia deklaracji. class, defi =wszystkie po prostu nadpisują wszelkie poprzednie zastosowania. repl.it
Challenger5,

@ Challenger5: masz rację, mój błąd, więc poprawna odpowiedź brzmi: najnowsza definicja się liczy, nie ma błędu w środowisku wykonawczym Pythona, ale nadal podobne zachowanie jak w przypadku każdej innej zmiennej.
Doc Brown

8
Zauważ, że namedtuplejest to zasadniczo deklaracja krótkiej ręki dla nowego typu z niezmiennymi atrybutami. Oznacza to, że odpowiedź brzmi: „Ani a tupleani a dict, ale object”. +1
jpmc26,

18

{„filename”: „blabla”, „size”: 123} lub po prostu („blabla”, 123)

Jest to odwieczne pytanie, czy kodować format / schemat wewnątrz pasma, czy poza pasmem.

Wymieniasz trochę pamięci, aby uzyskać czytelność i przenośność, która wynika z wyrażenia formatu danych bezpośrednio w danych. Jeśli tego nie zrobisz, wiedza, że ​​pierwsze pole to nazwa pliku, a drugie to rozmiar, musi zostać zachowane w innym miejscu. Oszczędza to pamięć, ale kosztuje czytelność i przenośność. Co będzie kosztować Twoją firmę więcej pieniędzy?

Jeśli chodzi o kwestię niezmienną, pamiętaj, że niezmienna nie oznacza bezużyteczności w obliczu zmiany. Oznacza to, że musimy pobrać więcej pamięci, wprowadzić zmiany w kopii i użyć nowej kopii. To nie jest darmowe, ale często nie stanowi przełomu. Używamy niezmiennych ciągów do zmiany rzeczy przez cały czas.

Innym aspektem jest rozszerzalność. Gdy przechowujesz dane tylko na miejscu, bez kodowania informacji o formacie, jesteś skazany tylko na pojedyncze dziedziczenie, co tak naprawdę jest niczym innym jak praktyką łączenia dodatkowych pól po ustalonych polach. Mogę zdefiniować trzecie pole jako datę utworzenia i nadal być zgodne z twoim formatem, ponieważ definiuję pierwszy i drugi w ten sam sposób.

Jednak nie mogę połączyć dwóch niezależnie zdefiniowanych formatów, które mają niektóre nakładające się pola, niektóre nie, przechowują je w jednym formacie i mogą być przydatne do rzeczy, które wiedzą tylko o jednym lub drugim formacie.

Aby to zrobić, muszę od początku zakodować informacje o formacie. Muszę powiedzieć „to pole to nazwa pliku”. Pozwala to na wielokrotne dziedziczenie.

Prawdopodobnie przywykłeś do dziedziczenia wyrażanego tylko w kontekście obiektów, ale te same pomysły działają dla formatów danych, ponieważ obiekty są przechowywane w formatach danych. To dokładnie ten sam problem.

Użyj więc tego, co uważasz za najbardziej potrzebne. Sięgam po elastyczność, chyba że mogę wskazać dobry powód, aby tego nie robić.


3
Szczerze mówiąc, wątpię, aby ktokolwiek, kto nie jest pewien między użyciem formatu wewnątrz pasma lub poza pasmem, ma tak rygorystyczne wymagania dotyczące wydajności, że musiałby użyć formatu poza pasmem
Alexander - Przywróć Monikę

2
@Alexander bardzo prawdziwe. Wolę uczyć ludzi o tym, aby rozumieli, na co patrzą, gdy mają do czynienia z rozwiązaniami pozapasmowymi. Formaty binarne często robią to ze względu na zaciemnianie. Nie każdy chce być przenośny. Jeśli chodzi o wydajność, jeśli naprawdę ma to znaczenie, rozważ kompresję przed skorzystaniem z funkcji poza pasmem.
candied_orange

Pamiętaj, że OP używa Pythona, więc prawdopodobnie nie są zbytnio zainteresowani wydajnością. Większość kodów wysokiego poziomu powinna być napisana z myślą o czytelności; przedwczesna optymalizacja jest źródłem wszelkiego zła.
Dagrooms

@Dagrooms nie nienawidzą Pythona. W wielu przypadkach działa dobrze. Ale poza tym zgadzam się ze wszystkim, co powiedziałeś. Chodziło mi o to, żeby powiedzieć: „To dlatego ludzie to robią.
candied_orange

@CandiedOrange Nie nienawidzę języka, używam go w codziennej pracy. Nie podoba mi się sposób, w jaki ludzie go używają.
Dagrooms

7

Użyłbym klasy o dwóch właściwościach. file.sizejest ładniejszy niż jeden file[1]lub file["size"].

Prosty jest lepszy niż złożony.


W przypadku, gdy ktoś się zastanawia: do generowania JSON, oba działają równie dobrze: file = Filesize(filename='stuff.txt', size=222)i filetup = ("stuff.txt", 222)oba generują ten sam JSON: json.dumps(file)i json.dumps(filetup)powodują:'["stuff.txt", 222]'
Juha Untinen

5

Czy nazwy plików są unikalne? Jeśli tak, możesz całkowicie zeskrobać listę i po prostu użyć czystego słownika dla wszystkich plików. np. (hipotetyczna strona internetowa)

{ 
  "/index.html" : 5467,
  "/about.html" : 3425,
  "/css/main.css" : 9876
}

itp...

Teraz nie dostajesz „nazwy” i „rozmiaru”, po prostu używasz klucza i wartości, ale często jest to bardziej naturalne. YMMV.

Jeśli naprawdę potrzebujesz „rozmiaru” dla zachowania przejrzystości lub potrzebujesz więcej niż jednej wartości dla pliku, to:

{ 
   "/index.html" : { "size": 5467, "mime_type" : "foo" },
   "/about.html" : { "size": 3425, "mime_type" : "foo" }
   "/css/main.css" : { "size": 9876, "mime_type" : "bar" }
}

0

W Pythonie słownik jest obiektem zmiennym. Z drugiej strony krotka jest niezmiennym przedmiotem.

jeśli chcesz zmienić klucz słownika, często paruj wartości lub za każdym razem. sugeruję użycie słownika.

jeśli masz stałe / statyczne dane, sugeruję użycie krotki.

# dictionary define.
a = {}
a['test'] = 'first value'

# tuple define.
b = ()
b = b+(1,)

# here, we can change dictionary value for key 'test'
a['test'] = 'second'

Ale nie można zmienić danych krotkowych za pomocą operatora przypisania.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.