Programování

Jak používat datové třídy Pythonu

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álKnihovnaSklad, 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žít vý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_ida 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)