Všechno v Pythonu je objekt, nebo se tak nějak říká. Pokud chcete vytvořit své vlastní objekty s jejich vlastními vlastnostmi a metodami, použijete Python třída
objekt, aby se to stalo. Ale vytváření tříd v Pythonu někdy znamená psaní spousty opakujících se kódů, které slouží k nastavení instance třídy z parametrů, které jí byly předány, nebo k vytvoření běžných funkcí, jako jsou operátory porovnání.
Datové třídy, zavedené v Pythonu 3.7 (a backportované do Pythonu 3.6), poskytují praktický způsob, jak třídy učinit méně podrobnými. Mnoho běžných věcí, které ve třídě děláte, například vytváření instancí vlastností z argumentů předaných třídě, lze omezit na několik základních pokynů.
Příklad datové třídy Pythonu
Zde je jednoduchý příklad konvenční třídy v Pythonu:
třídní kniha:'' 'Objekt pro sledování fyzických knih ve sbírce.' ''
def __init __ (self, name: str, weight: float, shelf_id: int = 0):
self.name = jméno
self.weight = hmotnost # v gramech, pro výpočet dopravy
self.shelf_id = police_id
def __repr __ (vlastní):
návrat (f "Book (name = {self.name! r}),
weight = {self.weight! r}, shelf_id = {self.shelf_id! r}) ")
Největší bolest hlavy je způsob, jakým je každý z argumentů předán__init__
musí být zkopírován do vlastností objektu. To není tak špatné, pokud máte co do činěníRezervovat
, ale co když se budete muset vypořádatRegál
, Knihovna
, Sklad
, a tak dále? Čím více kódu budete muset ručně psát, tím větší je šance, že uděláte chybu.
Tady je stejná třída Pythonu, implementovaná jako datová třída Pythonu:
from dataclasses import dataclass @dataclass class Book: '' 'Objekt pro sledování fyzických knih ve sbírce.' '' name: str weight: float shelf_id: int = 0
Když zadáte vlastnosti, nazývá sepole, v datové třídě,@dataclass
automaticky generuje veškerý kód potřebný k jejich inicializaci. Zachovává také informace o typu pro každou vlastnost, takže pokud používáte kódový linter jakomypy
, zajistí, že konstruktoru třídy dodáváte správné druhy proměnných.
Další věc@dataclass
does behind the scenes is automatically create code for a number of common dunder methods in the class. V konvenční třídě výše jsme si museli vytvořit vlastní__repr__
. V datové třídě je to zbytečné;@dataclass
generuje__repr__
pro tebe.
Jakmile je datová třída vytvořena, je funkčně identická s běžnou třídou. Neexistuje žádný výkonnostní trest za použití datové třídy, s výjimkou minimální režie dekoratéra při deklaraci definice třídy.
Přizpůsobte pole datové třídy Pythonu pomocípole
funkce
Výchozí způsob fungování datových tříd by měl být pro většinu případů použití v pořádku. Někdy však musíte doladit, jak se inicializují pole ve vaší datové třídě. K tomu můžete použítpole
funkce.
z datové třídy importovat datovou třídu, pole od psaní importu List @dataclass třída Kniha: '' 'Objekt pro sledování fyzických knih ve sbírce.' '' název: str podmínka: str = pole (porovnat = False) hmotnost: float = pole (výchozí = 0,0, repr = False) shelf_id: int = 0 kapitol: Seznam [str] = pole (default_factory = seznam)
Když nastavíte výchozí hodnotu na instancipole
, mění způsob nastavení pole podle toho, jaké parametry zadátepole
. Toto jsou nejčastěji používané možnosti pro pole
(existují i další):
výchozí
: Nastaví výchozí hodnotu pro pole. Musíte použítvýchozí
pokud a) používátepole
Chcete-li změnit jakékoli další parametry pole, ab) chcete nastavit výchozí hodnotu v poli nad tím. V tomto případě použijemevýchozí
stanovithmotnost
na0.0
.default_factory
: Poskytuje název funkce, která nebere žádné parametry a vrací nějaký objekt, který bude sloužit jako výchozí hodnota pro pole. V tomto případě chcemekapitoly
být prázdný seznam.repr
: Ve výchozím stavu (Skutečný
), řídí, zda se dané pole zobrazuje v automaticky generovaném__repr__
pro datovou třídu. V takovém případě nechceme, aby byla v knize uvedena váha knihy__repr__
, takže používámerepr = False
vynechat to.porovnat
: Ve výchozím stavu (Skutečný
), zahrnuje pole v metodách porovnání automaticky generovaných pro datovou třídu. Tady nechcemestav
být použit jako součást srovnání pro dvě knihy, tak jsme nastaviliporovnat =
Nepravdivé
.
Všimněte si, že jsme museli upravit pořadí polí tak, aby byla výchozí pole na prvním místě.
Použití__post_init__
k ovládání inicializace datové třídy Pythonu
V tuto chvíli vás asi zajímá: Pokud__init__
metoda datové třídy se generuje automaticky, jak získám kontrolu nad procesem init, abych mohl provést jemnější změny?
Zadejte__post_init__
metoda. Pokud zahrnete__post_init__
metoda v definici datové třídy, můžete poskytnout pokyny pro úpravu polí nebo jiných dat instance.
z datové třídy import datové třídy, pole od psaní importu Seznam @ třída datové třídy Kniha: '' 'Objekt pro sledování fyzických knih ve sbírce.' '' název: str hmotnost: float = pole (výchozí = 0,0, repr = nepravdivé) shelf_id: int = field (init = False) kapitoly: List [str] = field (default_factory = list) podmínka: str = field (default = "Good", porovnání = False) def __post_init __ (self): if self.condition == "zahozeno ": self.shelf_id = Žádný jiný: self.shelf_id = 0
V tomto příkladu jsme vytvořili a__post_init__
způsob nastavení police_id
naŽádný
pokud je stav knihy inicializován jako„Vyřazeno“
. Všimněte si, jak používámepole
inicializovatpolice_id
a projítinic
tak jakoNepravdivé
napole
. To znamenápolice_id
nebude inicializováno v__init__
.
PoužitíInitVar
k ovládání inicializace datové třídy Pythonu
Dalším způsobem, jak přizpůsobit nastavení datové třídy Pythonu, je použití souboruInitVar
typ. To vám umožní určit pole, které bude předáno__init__
a pak do__post_init__
, ale nebudou uloženy v instanci třídy.
Používáním InitVar
, můžete nastavit parametry při nastavování datové třídy, které se používají pouze během inicializace. Příklad:
z importu datových tříd datová třída, pole, InitVar ze zadaného importu Seznam Seznam @ třída Dataclass Kniha: '' 'Objekt pro sledování fyzických knih ve sbírce.' '' název: str podmínka: InitVar [str] = Žádná váha: float = pole (výchozí = 0,0, repr = False) shelf_id: int = field (init = False) kapitoly: Seznam [str] = pole (default_factory = seznam) def __post_init __ (self, podmínka): pokud podmínka == "Vyřazeno": self.shelf_id = Žádný jiný: self.shelf_id = 0
Nastavení typu pole naInitVar
(přičemž jeho podtyp je skutečný typ pole) signály do@dataclass
nedělat toto pole do pole datové třídy, ale předávat data spolu__post_init__
jako argument.
V této verzi našíRezervovat
třídy, neukládámestav
jako pole v instanci třídy. Používáme pouze stav
během inicializační fáze. Pokud to najdemestav
byl nastaven na„Vyřazeno“
, jsme si stanovilipolice_id
naŽádný
- ale neukládámestav
v instanci třídy.
Kdy použít datové třídy Pythonu - a kdy je nepoužívat
Jeden běžný scénář pro použití datových tříd je jako náhrada za pojmenovanou třídu. Datové třídy nabízejí stejné chování a další a lze je změnit (stejně jako pojmenované tuple) jednoduše pomocí@dataclass (frozen = True)
jako dekoratér.
Dalším možným případem použití je nahrazení vnořených slovníků, se kterými je obtížné pracovat, za vnořené instance datových tříd. Pokud máte datovou tříduKnihovna
, s vlastností seznamupolice
, můžete použít datovou tříduČítárna
naplnit tento seznam a poté přidat metody, které usnadní přístup k vnořeným položkám (např. kniha na polici v konkrétní místnosti).
Ale ne každá třída Pythonu musí být datovou třídou. Pokud vytváříte třídu hlavně jako způsob, jak seskupit spoustustatické metody, nikoli jako kontejner pro data, nemusíte z něj dělat datovou třídu. Například běžný vzor s analyzátory je mít třídu, která přebírá strom abstraktní syntaxe, prochází strom a odesílá volání různých metod ve třídě na základě typu uzlu. Protože třída analyzátoru má velmi málo vlastních dat, datová třída zde není užitečná.
Jak udělat víc s Pythonem
- Začněte s asynchronizací v Pythonu
- Jak používat asyncio v Pythonu
- Jak používat PyInstaller k vytvoření spustitelných souborů Pythonu
- Výukový program pro Cython: Jak zrychlit Python
- Jak chytře nainstalovat Python
- Jak spravovat projekty v Pythonu pomocí Poetry
- Jak spravovat projekty Pythonu pomocí Pipenv
- Virtualenv a venv: Vysvětlení virtuálních prostředí Pythonu
- Python virtualenv a venv dělá a nedělá
- Vysvětlení vláken a podprocesů v Pythonu
- Jak používat debugger Pythonu
- Jak používat timeit k profilování kódu Pythonu
- Jak používat cProfile k profilování kódu Pythonu
- Jak převést Python na JavaScript (a zpět)