Dzisiaj pytanie bardziej opisowe, chociaż będą też przykłady.
Co to jest nazwana tupla (ang. named tuple) i czym się różni od zwykłej tupli ? Kiedy należy ją użyć i jakie problemy rozwiązuje ?
Czemu używamy tupli
Tuple zaraz po listach są chyba najczęściej używanymi strukturami danych w Pythonie. Ja trzymam się zasady: zawsze jeśli tylko się da, użyj tupli. Tuple są lżejsze, szybsze oraz lepiej radzą sobie w świecie wielowątkowych aplikacji. Generalnie jeśli potrzebujesz trzymać swoje dane w kolekcji i nie masz zamiaru ich zmieniać, czy też dodawać do nich nowych pozycje, sięgasz po tuple. Niezmienność tupli (tuple są immutable) niejako gwarantuje nam, że co by się nie działo, nasze dane pozostaną takie jak były. Należy korzystać z tej cechy tak często jak to możliwe.
Ograniczenia tupli
Mimo wielu zalet tuple mają też wady. I nie chodzi tu o brak możliwości ich edycji. Tą cechę trzeba zaakceptować. Jeśli Ci to przeszkadza to prawdopodobnie do rozwiązania tego konkretnego problemu potrzebujesz listy albo jakiejś innej kolekcji danych. Tuple wprowadzają nam bałagan. Za przykład niech posłuży nam taka tupla:
szafa = (180, 90, 70)
Nasza tupla o nazwie szafa posiada trzy wartości. Wysokość, szerokość oraz głębokość. Jednym słowem są to wymiary tej szafy. Problem z tym, że ja to wiem bo przed chwilą to napisałem. Jeśli zajrzałbym do takiego kodu za tydzień pewnie już bym tego nie pamiętał. Co ma powiedzieć osoba, która dostaje taki kod po nas. Nie mówiąc już o tym, że nie ma żadnego sensownego sposobu by zorientować się, która wartość reprezentuje wysokość, czy też szerokość naszej szafy. Czytelność kodu ma duże znaczenie. Trzeba coś z tym zrobić.
A może słownik ?
Użycie słownika w tym przypadku znacząco zwiększy czytelność kodu:
szafa = {'wysokosc': 180, 'szerokosc':90, 'glebokosc':70} print(szafa['wysokosc'] print(szafa)
Output:
180 {'wysokosc': 180, 'szerokosc': 90, 'glebokosc': 70}
Uzyskaliśmy ładny sposób dostępu do naszych danych. Nasz słownik ładnie też się wyświetla. To co straciliśmy to niezmienność. Słownik jest typem zmiennym, a więc w trakcie wykonywania programu możemy go modyfikować. Nie o to nam chodziło.
A może klasa ?
Klasa wraz ze swoimi polami również będzie wygodnym kontenerem na trzymanie naszych informacji:
class Szafa: def __init__(self, wysokosc, szerokosc, glebokosc): self.wysokosc = wysokosc self.szerokosc = szerokosc self.glrbokosc = glebokosc szafa = Szafa(180, 90, 70) print(szafa) print(szafa.wysokosc)
Output:
<__main__.Szafa object at 0x7fbadc148710> 180
Niestety obiekty klasy nie wyświetlają się już tak ładnie. Oczywiście można by i to naprawić poprzez implementacje odpowiedniej magicznej metody. Dodatkowo znowu mamy problem ze zmiennością naszej instancji. Obiekty klasy nie są immutable. Przydałaby się nam klasa której nie da się zmieniać.
Named tuple czyli tupla nazwana
Na ratunek przybywa nam tupla nazwana. Jest to coś pomiędzy klasą, a zwykłą tuplą. Dodatkowo jest immutable, a o to przecież nam chodziło.
from collections import namedtuple Szafa = namedtuple('Szafa', ['wysokosc', 'szerokosc', 'glebokosc']) szafa = Szafa(180, 90 ,70) print(szafa.wysokosc) print(szafa)
Output:
180 Szafa(wysokosc=180, szerokosc=90, glebokosc=70)
Teraz można odwoływać się do poszczególnych pól zarówno poprzez indeks jak w zwykłej tupli oraz za pomocą nazw parametrów.
Zachęcam do używania argumentów w postaci słów kluczowych podczas tworzenia naszej tupli szafa = Szafa(wysokosc=180, szerokosc=90, glebokosc=70)
Podsumowanie
Tuple nazwane są bardzo pomocne. To czego nam nie oferują to domyślne parametry pół w tuplach podczas ich tworzenia. Jako ciekawostka ten problem można też rozwiązać, ale to już temat na inny wpis. Miłej zabawy z tuplami.
Można użyć tak jak pisałeś klasy ale udekorowanej jako @dataclass, a po dodaniu @dataclass(frozen=True) klasa będzie nie zmiennna. Chyba dobrze jest używać jako kontenery danych, tak udekorowanych klas, nie wymagają one też użycia __init__
https://repl.it/@SlawekM/dataclass