Luokan ja instanssimuuttujien välinen ero selitetään.
Muuttujat ovat pohjimmiltaan symboleja, jotka edustavat arvoa, jota käytämme ohjelmassa. Oliosuuntautunut ohjelmointi mahdollistaa muuttujien käytön luokka- tai instanssitasolla. Tämän artikkelin tavoitteena on tehdä selvä ero Pythonin oliomallin tarjoamien muuttujatyyppien välillä, ja sen jälkeen käsitellään tarkemmin erästä erikoista käyttäytymistä, joka voi johtaa yllättäviin tuloksiin, jos se jätetään huomiotta. Pureudutaan siis asiaan!
Pythonin oliomallin mukaan Python-objekteilla on kahdenlaisia data-attribuutteja: luokkamuuttujat ja instanssimuuttujat.
Luokkamuuttujat – Ilmoitetaan luokkamäärittelyn sisällä (mutta minkään instanssimetodin ulkopuolella). Niitä ei ole sidottu mihinkään tiettyyn luokan objektiin, joten ne ovat yhteisiä kaikille luokan objekteille. Luokkamuuttujan muuttaminen vaikuttaa kaikkiin objektien instansseihin samanaikaisesti.
Instanssimuuttuja – Ilmoitetaan luokan konstruktorimetodin sisällä (__init__
-metodi). Ne on sidottu luokan tiettyyn objekti-instanssiin, joten instanssimuuttujan sisältö on täysin riippumaton objekti-instanssista toiseen.
Aloitetaan lyhyellä ja helposti sulatettavalla esimerkillä:
class Car:
wheels = 4 # <- Class variable def __init__(self, name):
self.name = name # <- Instance variable
Ylhäällä on määritelty perusluokka Car, jossa ei ole mitään hienouksia. Jokaisella sen instanssilla on luokkamuuttuja wheels yhdessä instanssimuuttujan nimen kanssa. Instansoidaan luokka, jotta päästään käsiksi muuttujiin.
>>> jag = Car('jaguar')
>>> fer = Car('ferrari')>>> jag.name, fer.name
('jaguar', 'ferrari')>>> jag.wheels, fer.wheels
(4, 4)>>> Car.wheels
4
Instanssimuuttujan nimen saaminen on melko suoraviivaista. Luokkamuuttujan käyttämiseen on kuitenkin hieman enemmän joustavuutta. Kuten edellä, voimme käyttää pyöriä objektin instanssin tai itse luokan kautta.
Yritämme myös käyttää nimeä luokan kautta, mikä johtaa AttributeErroriin, koska instanssimuuttujat ovat objektikohtaisia ja ne luodaan, kun __init__
konstruktoria kutsutaan. Tämä on keskeinen ero luokan ja instanssimuuttujien välillä.
>>> Car.name
AttributeError: type object 'Car' has no attribute 'name'
Nyt oletetaan toistaiseksi, että Jaguar-autossamme on kolme pyörää. (kyllä, se on tyhmää, mutta kestäkää se!!! 😅). Esittääksemme sen koodissamme voimme muuttaa muuttujaa wheels.
>>> Car.wheels = 3
Mitä teimme edellä, tekee kaikista autoista 3-pyöräisiä, koska olemme muuttaneet luokkamuuttujaa, joka koskee kaikkia Car-luokan instansseja.
>>> jag.wheels, fer.wheels
(3, 3)
Siten luokkamuuttujan muuttaminen luokan nimiavaruudessa vaikuttaa kaikkiin luokan instansseihin. Otetaan muutos takaisin ja muokataan pyörät-muuttujaa jag-objektin avulla.
>>> Car.wheels = 4
>>> jag.wheels = 3
Tällöin saamme haluamamme tuloksen.
>>> jag.wheels, fer.wheels, Car.wheels
(3, 4, 4)
Vaikka saimmekin haluamamme tuloksen, mutta mitä tapahtui kulissien takana, on uusi pyörät-muuttuja, joka on lisätty jag-objektiin, ja tämä uusi muuttuja varjostaa samannimistä luokkamuuttujaa, ohittaa ja piilottaa sen. Voimme käyttää molempia wheels-muuttujia seuraavasti:
>>> jag.wheels, jag.__class__.wheels
(3, 4)
Siten voimme päätellä, että jag.wheels = 3
loi uuden instanssimuuttujan, jolla on sama nimi kuin luokkamuuttujalla (wheels). Tämä on tärkeä käsite, joka on syytä tiedostaa.
Käyttämällä luokka- ja instanssikohtaisia muuttujia voidaan varmistaa, että koodimme noudattaa DRY-periaatetta toistojen vähentämiseksi koodissa.
Tämän tietäminen voi mielestäni olla todella kätevää ja säästää jonain päivänä monta tuntia virheenkorjausta. 😇
Viittaa tähän postaukseeni lukeaksesi lisää erilaisista metodeista (instanssi, luokka & staattinen) Pythonissa.
Konkluusioita
- Luokkamuuttujat jaetaan kaikkien objektien kesken, kun taas instanssimuuttujat ovat kullekin instanssille ominaista dataa varten.
- Instanssimuuttuja ohittaa samannimiset luokkamuuttujat, mikä voi vahingossa aiheuttaa koodissamme bugeja tai yllätyksellistä käyttäytymistä.[/>]