Alt i Python er et objekt, eller så sier ordtaket. Hvis du vil lage dine egne egendefinerte objekter, med egne egenskaper og metoder, bruker du Pythons klasse
innvending for å få det til. Men å opprette klasser i Python betyr noen ganger å skrive massevis av repeterende kokerplatekode for å sette opp klasseinstansen fra parametrene som sendes til den, eller for å lage vanlige funksjoner som sammenligningsoperatorer.
Dataklasser, introdusert i Python 3.7 (og backported til Python 3.6), gir en praktisk måte å gjøre klassene mindre detaljerte. Mange av de vanligste tingene du gjør i en klasse, som å sette i gang egenskaper fra argumentene som sendes til klassen, kan reduseres til noen få grunnleggende instruksjoner.
Python dataklasseeksempel
Her er et enkelt eksempel på en konvensjonell klasse i Python:
class Book:'' 'Objekt for sporing av fysiske bøker i en samling.' ''
def __init __ (selv, navn: str, vekt: float, shelf_id: int = 0):
self.name = navn
egenvekt = vekt # i gram, for beregning av frakt
self.shelf_id = shelf_id
def __repr __ (selv):
returner (f "Book (name = {self.name! r},
vekt = {self.weight! r}, shelf_id = {self.shelf_id! r}) ")
Den største hodepinen her er måten hvert av argumentene overføres til__i det__
må kopieres til objektets egenskaper. Dette er ikke så ille hvis du bare har å gjøre medBok
, men hva om du må forholde deg tilBokhylle
, Bibliotek
, Lager
, og så videre? Dessuten, jo mer kode du må skrive for hånd, jo større er sjansene for at du tar feil.
Her er den samme Python-klassen, implementert som en Python-dataklasse:
fra dataclasses importer dataclass @dataclass class Bok: '' 'Objekt for sporing av fysiske bøker i en samling.' '' navn: str vekt: float shelf_id: int = 0
Når du spesifiserer egenskaper, kaltEnger, i en dataklasse,@dataclass
genererer automatisk all koden som trengs for å initialisere dem. Det bevarer også typeinformasjonen for hver eiendom, så hvis du bruker en kodelinter sommypy
, vil det sikre at du leverer de riktige variablene til klassekonstruktøren.
En annen ting@dataclass
gjør bak kulissene er å automatisk lage kode for en rekke vanlige dundermetoder i klassen. I den konvensjonelle klassen ovenfor måtte vi lage våre egne__repr__
. I dataklassen er dette unødvendig;@dataclass
genererer__repr__
for deg.
Når en dataklasse er opprettet, er den funksjonelt identisk med en vanlig klasse. Det er ingen ytelsesstraff for å bruke en dataklasse, bortsett fra den minimale kostnaden for dekoratøren når man erklærer klassedefinisjonen.
Tilpass Python dataklassefelt medfelt
funksjon
Standard måten dataklasser fungerer på, bør være greit for de fleste brukssaker. Noen ganger må du finjustere hvordan feltene i dataklassen din initialiseres. For å gjøre dette kan du brukefelt
funksjon.
fra dataklasser importerer dataklasse, felt fra å skrive import Liste @dataclass klasse Bok: '' 'Objekt for sporing av fysiske bøker i en samling.' '' navn: str tilstand: str = felt (sammenlign = Falsk) vekt: float = felt (standard = 0.0, repr = False) shelf_id: int = 0 kapitler: Liste [str] = felt (default_factory = liste)
Når du angir en standardverdi til en forekomst avfelt
, det endrer hvordan feltet er satt opp avhengig av hvilke parametere du girfelt
. Dette er de mest brukte alternativene for felt
(det er andre):
misligholde
: Angir standardverdien for feltet. Du må brukemisligholde
hvis du a) brukerfelt
for å endre andre parametere for feltet, og b) du vil angi en standardverdi på feltet på toppen av det. I dette tilfellet bruker vimisligholde
å settevekt
til0.0
.standard_fabrikk
: Gir navnet på en funksjon, som ikke tar noen parametere, som returnerer noe objekt for å fungere som standardverdien for feltet. I dette tilfellet vil vikapitler
å være en tom liste.repr
: Som standard (ekte
), kontrollerer om det aktuelle feltet vises i det automatisk genererte__repr__
for dataklassen. I dette tilfellet ønsker vi ikke at bokens vekt vises i__repr__
, så vi brukerrepr = Falsk
å utelate det.sammenligne
: Som standard (ekte
), inkluderer feltet i sammenligningsmetodene som automatisk genereres for dataklassen. Her vil vi ikketilstand
skal brukes som en del av sammenligningen for to bøker, så vi settersammenligne =
Falsk
.
Merk at vi har måttet justere rekkefølgen på feltene slik at ikke-standardfeltene kommer først.
Bruk__post_init__
for å kontrollere initialisering av Python-dataklasse
På dette punktet lurer du sannsynligvis på: Hvis__i det__
metoden til en dataklasse genereres automatisk, hvordan får jeg kontroll over init-prosessen for å gjøre mer detaljerte endringer?
Skriv inn__post_init__
metode. Hvis du inkluderer__post_init__
metode i dataklasse-definisjonen din, kan du gi instruksjoner for å endre felt eller andre forekomstdata.
fra dataklasser importerer dataklasse, felt fra å skrive import Liste @dataclass klasse Bok: '' 'Objekt for sporing av fysiske bøker i en samling.' '' navn: str vekt: float = felt (standard = 0.0, repr = Falsk) shelf_id: int = felt (init = Falsk) kapitler: Liste [str] = felt (standard_fabrikk = liste) tilstand: str = felt (standard = "Bra", sammenlign = Falsk) def __post_init __ (selv): hvis selvbetingelse == "Forkastet ": self.shelf_id = Ingen andre: self.shelf_id = 0
I dette eksemplet har vi opprettet en__post_init__
metode for å sette shelf_id
tilIngen
hvis bokens tilstand initialiseres som"Forkastet"
. Legg merke til hvordan vi brukerfelt
å initialisereshelf_id
, og passerei det
somFalsk
tilfelt
. Dette betyrshelf_id
vil ikke bli initialisert i__i det__
.
BrukInitVar
for å kontrollere initialisering av Python-dataklasse
En annen måte å tilpasse Python dataklasseoppsett på er å brukeInitVar
type. Dette lar deg spesifisere et felt som skal sendes til__i det__
og deretter til__post_init__
, men lagres ikke i klasseinstansen.
Ved bruk av InitVar
, kan du ta inn parametere når du setter opp dataklassen som bare brukes under initialisering. Et eksempel:
fra dataklasser importerer dataklasse, felt, InitVar fra å skrive import Liste @dataclass klasse Bok: '' 'Objekt for sporing av fysiske bøker i en samling.' '' navn: str tilstand: InitVar [str] = Ingen vekt: float = felt (standard = 0.0, repr = False) shelf_id: int = field (init = False) kapitler: Liste [str] = field (default_factory = list) def __post_init __ (self, condition): if condition == "Forkastet": self.shelf_id = Ingen andre: self.shelf_id = 0
Setter feltets type tilInitVar
(med undertype som den faktiske feltypen) signaliserer til@dataclass
å ikke gjøre det feltet til et dataklassefelt, men å overføre dataene til__post_init__
som argument.
I denne versjonen av vårBok
klasse lagrer vi ikketilstand
som et felt i klasseinstansen. Vi bruker bare tilstand
under initialiseringsfasen. Hvis vi finner dettilstand
ble satt til"Forkastet"
, vi settershelf_id
tilIngen
- men vi lagrer ikketilstand
i klasseinstansen.
Når skal du bruke Python-dataklasser - og når ikke å bruke dem
Et vanlig scenario for bruk av dataklasser er som erstatning for navngitt tuple. Databriller har samme oppførsel og mer, og de kan gjøres uforanderlige (som navngitte tinninger er) ved å bare bruke@dataclass (frossen = sann)
som dekoratør.
En annen mulig brukssak er å erstatte nestede ordbøker, som kan være klønete å jobbe med, med nestede forekomster av dataklasser. Hvis du har en dataklasseBibliotek
, med en listeegenskaphyller
, kan du bruke en dataklasseLeserom
å fylle ut listen, og deretter legge til metoder for å gjøre det enkelt å få tilgang til nestede gjenstander (f.eks. en bok på en hylle i et bestemt rom).
Men ikke alle Python-klasser trenger å være en dataklasse. Hvis du oppretter en klasse hovedsakelig som en måte å gruppere en haug medstatiske metoder, i stedet for som en beholder for data, trenger du ikke gjøre det til en dataklasse. For eksempel er et vanlig mønster med parsere å ha en klasse som tar et abstrakt syntaks-tre, går i treet og sender anrop til forskjellige metoder i klassen basert på nodetypen. Fordi parserklassen har svært lite data, er en dataklasse ikke nyttig her.
Hvordan gjøre mer med Python
- Kom i gang med asynkronisering i Python
- Hvordan bruke asyncio i Python
- Hvordan bruke PyInstaller for å lage Python-kjørbare filer
- Cython tutorial: Hvordan øke hastigheten på Python
- Slik installerer du Python på den smarte måten
- Hvordan håndtere Python-prosjekter med poesi
- Hvordan administrere Python-prosjekter med Pipenv
- Virtualenv og venv: Python virtuelle miljøer forklart
- Python virtualenv og venv do’s and don'ts
- Python-tråder og underprosesser forklart
- Hvordan bruke Python-feilsøkingsprogrammet
- Hvordan bruke timeit til å profilere Python-kode
- Hvordan bruke cProfile for å profilere Python-kode
- Slik konverterer du Python til JavaScript (og tilbake igjen)