Przegląd
Pytanie zostało rozwiązane. Jednak ta odpowiedź zawiera kilka praktycznych przykładów, które mogą pomóc w podstawowym zrozumieniu klas danych.
Czym dokładnie są klasy danych Pythona i kiedy najlepiej ich używać?
- generatory kodu : generuj kod standardowy; możesz zdecydować się na zaimplementowanie specjalnych metod w zwykłej klasie lub zaimplementować je automatycznie w klasie danych.
- kontenery danych : struktury przechowujące dane (np. krotki i dykty), często z kropkami, dostęp do atrybutów, takich jak klasy
namedtuple
i inne .
„zmienne nazwane tuleje z domyślnymi [s]”
Oto, co oznacza to drugie zdanie:
- zmienne : domyślnie dataclass atrybuty mogą być przypisane. Opcjonalnie możesz uczynić je niezmiennymi (patrz Przykłady poniżej).
- namedtuple : masz kropkowany dostęp do atrybutów, taki jak a
namedtuple
lub zwykła klasa.
- domyślne : możesz przypisać wartości domyślne do atrybutów.
W porównaniu z typowymi klasami oszczędzasz przede wszystkim na wpisywaniu standardowego kodu.
cechy
To jest przegląd funkcji klasy danych (TL; DR? Zobacz tabelę podsumowującą w następnej sekcji).
Co dostałeś
Oto funkcje, które domyślnie uzyskujesz z klas danych.
Atrybuty + reprezentacja + porównanie
import dataclasses
@dataclasses.dataclass
#@dataclasses.dataclass() # alternative
class Color:
r : int = 0
g : int = 0
b : int = 0
Te wartości domyślne są zapewniane przez automatyczne ustawienie następujących słów kluczowych na True
:
@dataclasses.dataclass(init=True, repr=True, eq=True)
Co możesz włączyć
Dodatkowe funkcje są dostępne, jeśli ustawiono odpowiednie słowa kluczowe True
.
Zamówienie
@dataclasses.dataclass(order=True)
class Color:
r : int = 0
g : int = 0
b : int = 0
Zaimplementowano teraz metody porządkowania (przeciążanie operatorów:) < > <= >=
, podobnie jak w functools.total_ordering
przypadku silniejszych testów równości.
Hashable, Mutable
@dataclasses.dataclass(unsafe_hash=True) # override base `__hash__`
class Color:
...
Chociaż obiekt jest potencjalnie zmienny (prawdopodobnie niepożądany), zaimplementowano skrót.
Hashable, Immutable
@dataclasses.dataclass(frozen=True) # `eq=True` (default) to be immutable
class Color:
...
Hash jest teraz zaimplementowany, a zmiana obiektu lub przypisywanie atrybutów jest niedozwolone.
Ogólnie rzecz biorąc, obiekt jest haszowalny, jeśli jest unsafe_hash=True
albo frozen=True
.
Zobacz także oryginalną tablicę haszującą z dodatkowymi szczegółami.
Czego nie dostajesz
Aby uzyskać następujące funkcje, należy ręcznie zaimplementować specjalne metody:
Rozpakowanie
@dataclasses.dataclass
class Color:
r : int = 0
g : int = 0
b : int = 0
def __iter__(self):
yield from dataclasses.astuple(self)
Optymalizacja
@dataclasses.dataclass
class SlottedColor:
__slots__ = ["r", "b", "g"]
r : int
g : int
b : int
Rozmiar obiektu jest teraz zmniejszony:
>>> imp sys
>>> sys.getsizeof(Color)
1056
>>> sys.getsizeof(SlottedColor)
888
W niektórych przypadkach __slots__
poprawia również szybkość tworzenia instancji i uzyskiwania dostępu do atrybutów. Ponadto gniazda nie pozwalają na przypisanie domyślne; w przeciwnym razie ValueError
podniesione jest a .
Więcej informacji o automatach znajdziesz w tym poście na blogu .
Tabelka podsumowująca
+----------------------+----------------------+----------------------------------------------------+-----------------------------------------+
| Feature | Keyword | Example | Implement in a Class |
+----------------------+----------------------+----------------------------------------------------+-----------------------------------------+
| Attributes | init | Color().r -> 0 | __init__ |
| Representation | repr | Color() -> Color(r=0, g=0, b=0) | __repr__ |
| Comparision* | eq | Color() == Color(0, 0, 0) -> True | __eq__ |
| | | | |
| Order | order | sorted([Color(0, 50, 0), Color()]) -> ... | __lt__, __le__, __gt__, __ge__ |
| Hashable | unsafe_hash/frozen | {Color(), {Color()}} -> {Color(r=0, g=0, b=0)} | __hash__ |
| Immutable | frozen + eq | Color().r = 10 -> TypeError | __setattr__, __delattr__ |
| | | | |
| Unpacking+ | - | r, g, b = Color() | __iter__ |
| Optimization+ | - | sys.getsizeof(SlottedColor) -> 888 | __slots__ |
+----------------------+----------------------+----------------------------------------------------+-----------------------------------------+
+ Te metody nie są generowane automatycznie i wymagają ręcznej implementacji w klasie danych.
* __ne__
nie jest potrzebne i dlatego nie jest realizowane .
Dodatkowe funkcje
Po inicjalizacji
@dataclasses.dataclass
class RGBA:
r : int = 0
g : int = 0
b : int = 0
a : float = 1.0
def __post_init__(self):
self.a : int = int(self.a * 255)
RGBA(127, 0, 255, 0.5)
# RGBA(r=127, g=0, b=255, a=127)
Dziedzictwo
@dataclasses.dataclass
class RGBA(Color):
a : int = 0
Konwersje
Konwersja dataclass na krotki lub dict, rekurencyjnie :
>>> dataclasses.astuple(Color(128, 0, 255))
(128, 0, 255)
>>> dataclasses.asdict(Color(128, 0, 255))
{r: 128, g: 0, b: 255}
Ograniczenia
Bibliografia
- Rozmowa R. Hettingera na temat klas danych: generator kodu kończący wszystkie generatory kodu
- T. Hunnera Dyskusja na Prostsze klas: Python klas bez wszystkich Cruft
- Dokumentacja Pythona dotycząca haszowania szczegółów
- Real Python's guide on The Ultimate Guide to Data Classes in Python 3.7
- A. Shaw post na blogu Krótka prezentacja klas danych w Pythonie 3.7
- Repozytorium github E. Smitha dotyczące klas danych
namedtuple
s są niezmienne i nie mogą mieć wartości domyślnych dla atrybutów, podczas gdy klasy danych są zmienne i mogą je mieć.