Viskas yra objektai
Python yra objektinė kalba. Jūs ne tik kad galite apsirašyti savo klases, bet beveik visi Pythone sutinkami dalykai jau yra objektai -- skaičiai, simbolių eilutės, sąrašai, funkcijos, klasės, objektai, metodai, moduliai.
Kas yra objektas? Bet kas, ką galima priskirti kintamajam, arba perduoti kaip argumentą funkcijai. Objektai turi metodus ir atributus -- metodus galima iškviesti, atributų reikšmes galima pasižiūrėti arba pakeisti.
x = [1, 2, 3] # sąrašas yra objektas, jį galime priskirti kintamajam x.append(5) # jis turi metodų
datetime
yra modulis (vienas iš Python 2.3
standartinės bibliotekos modulių). Moduliai taip pat yra objektai. Modulių
atributai yra visi kintamieji, funkcijos bei klasės, aprašytos modulyje.
import datetime dt = datetime.date(2004, 9, 13) print dt.year # 2004 print dt.weekday() # savaitės diena (0 - pirmadienis, 6 - sekmadienis)
datetime.date
yra klasė. Kintamajam dt
priskiriamas šios klasės
egzempliorius. Matome, kad date
klasės egzempliorai
turi ir atributų, ir metodų.
Klasės taip pat objektai. Klasių egzemplioriai sukuriami iškviečiant klasę kaip funkciją.
import datetime cls = datetime.date dt = cls(2004, 9, 13)
Funkcijos irgi objektai. Jas galima priskyrinėti kintamiesiems ir paskui iškvietinėti.
import math fn = math.sin print fn(0) # 0.0 fn = math.cos print fn(0) # 1.0
Objektų metodai irgi yra objektai -- labai panašūs į funkcijas.
a = 'labas'.upper b = 'rytas'.capitalize print a(), b() # LABAS Rytas
Tiesą sakant, skirtumas tarp objektų metodų ir atributų yra labai nežymus.
def global_function(): print "global_function()" class MyClass: def method(self): print "method()" print self.n obj = MyClass() obj.n = 43 # atributas, kurio reikšmė - skaičius obj.f = global_function # atributas, kurio reikšmė - funkcija obj.method() # kviečiam metodą obj.f() # kviečiam funkciją
Kai kviečiame metodą, jis gauna argumentą self
,
kai kviečiame funkciją, priskirtą objekto atributui, funkcija šio argumento
negauna.
from datetime import date a_date = date(2004, 9, 14) another_date = date(2004, 9, 15) bound_method = a_date.weekday # objekto atributas -- susietas metodas unbound_method = date.weekday # klasės atributas -- nesusietas metodas print bound_method() # susietas metodas žino self reikšmę print unbound_method(a_date) # nesusietam metodui reikia nurodyti self
Galima funkciją paversti metodu:
def global_function(self): print self.n class MyClass: def __init__(self, n): # konstruktorius self.n = n def method(self): print self.n obj = MyClass(42) obj.method() # spausdins 42 MyClass.f = global_function # priskiriame atributą klasei, o ne objektui obj.f() # visi tos klasės objektai įgauna naują metodą
Introspekcija
Kai turime bet kokį objektą, galime sužinoti visus jo atributus ir metodus.
x = "labas" print dir(x) # atspausdins krūvą metodų, tarp jų ir 'upper' y = 42 print dir(x) # atspausdins krūvą specialių metodų, realizuojančių # aritmetines ir kitas operacijas
Gauti objekto atributą žinant jo vardą galima su funkcija getattr
import datetime a_date = datetime.date(2004, 9, 11) attribute = 'year' print getattr(a_date, attribute)
Patikrinti, ar objektas yra iškviečiamas, galime su funkcija callable
. Iškviečiami objektai yra funkcijos, metodai,
klasės, o taip pat klasių egzemplioriai, turintys metodą su specialiu
pavadinimu __call__
.
def methods_of_an_object(obj): methods = [] for name in dir(obj): attribute = getattr(obj, name) if callable(attribute): methods.append(name) return methods import datetime print methods_of_an_object(datetime.date(2004, 9, 8)) # Spausdins metodus tokius kaip weekday, bet neminės atributų, tokių kaip year
Galima tai užrašyti trumpiau, pritaikius konstrukciją, angliškai vadinama list comprehension
def methods_of_an_object(obj): return [name for name in dir(obj) if callable(getattr(obj, name))] import datetime print methods_of_an_object(datetime.date(2004, 9, 8)) # Spausdins metodus tokius kaip weekday, bet neminės atributų, tokių kaip year
Klasių, funkcijų bei metodų dokumentacija pasiekiama kaip atributas
__doc__
def sum(x, y): """Return the sum of two arguments""" return x + y print sum.__doc__
Vadinasi, turint bet kokį objektą (modulį, klasę, funkciją) galima sukurti
jo aprašymą, mininti to objekto atributus, metodus ir tų metodų dokumentaciją.
Pythonas jau turi tokią funkciją -- help
import sys help(sys) # sys modulio dokumentacija help(str) # str klasės dokumentacija
Ši dokumentacija taip pat pasiekiama iš komandų eilutės, naudojant programą
pydoc
Vardai ir objektai
Python kintamieji (o taip pat ir atributai) iš tiesų tėra tik vardai, priskirti objektams. Tam pačiam objektui galima priskirti kelis vardus:
x = [1, 2, 3] y = x # sąrašas [1, 2, 3] turi du vardus -- x ir y z = [1, 2, 3] # kitas sąrašas su tokiu pat turiniu turi vardą z x.append(4) # pakeičiame sąrašą print x # spausdins [1, 2, 3, 4] print y # spausdins [1, 2, 3, 4], nes tai tas pats objektas print z # spausdins [1, 2, 3], nes tai kitas objektas
Objektus galima kopijuoti
x = [1, 2, 3] y = list(x) # sąrašo x kopija; dar tai galima užrašyti y = x[:] x.append(4) # pakeičiame sąrašą print x # spausdins [1, 2, 3, 4] print y # spausdins [1, 2, 3], nes tai kitas objektas
Standartinėje bibliotekoje yra modulis copy
,
leidžiantis kopijuoti gilius objektų grafus. Praktikoje jo prireikia labai
retai.
Objektus galima lyginti pagal jų reikšmę, arba pagal jų identitetą
x = [1, 2, 3] y = x z = list(x) print x == y # True print x == z # True print x is y # True, nes tai tas pats objektas print x is z # False, nes tai skirtingi objektai
None
Pythonas turi konstantą None
, kuri daugmaž
atitinka SQLo bei C/C++ NULL arba Paskalio nil. Ši konstanta -- vienintėlis
egzistuojantis NoneType klasės objektas. Idiomatiškas palyginimas, ar
kintamojo reikšmė yra None
, yra
if obj is None: print "None" else: print "ne None"
None
dažnai naudojama kaip nutylėta (angl. default) funkcijos
argumento reikšmė
def trikampis(a, b, c=None): """Skaičiuoja trikampio su kraštinėmis a, b ir c plotą. Jei kraštinė c nenurodyta, laikoma, kad a ir b yra stataus trikampio statiniai, ir įžambinė c suskaičiuojama automatiškai. """ if c is None: c = (a ** 2 + b ** 2) ** 0.5 s = (a + b + c) / 2.0 return (s * (s - a) * (s - b) * (s - c)) ** 0.5
Specialūs metodai
Tarkime, kad jūs turite klasę Vector
. Kaip
paaiškinti Pythonui, kaip reikia lyginti vektorius?
class Vector: def __init__(self, x, y): self.x = x self.y = y def __eq__(self, other): """v1 == v2""" return self.x == other.x and self.y == other.y def __ne__(self, other): """v1 != v2""" return self.x != other.x or self.y != other.y # arba # return not self == other # arba # return not self.__eq__(other)
Jei neaprašysime metodo __eq__
, Pytonas lygins
vektorius pagal identitetą.
Yra nemažas rinkinys operatorių, kuriuos galima realizuoti aprašant metodus
specialiais vardais -- __add__
, __sub__
, __mul__
, __div__
, __mod__
ir taip
toliau. Pilną jų sąrašą rasite Python
dokumentacijoje.
Kintami bei nekintami objektai
Kai kuriuos objektus galima keisti (pvz., aukščiau aprašytos Vector
klasės objektams galime pakeisti atributo
x
reikšmę) -- jie yra kintami (angl.
mutable). Kitų objektų keisti negalima (pvz., simbolių eilučių,
skaičių, tuplų, datų) -- jie yra nekintami (angl. immutable).
Su nekintamais objektais dirbti paprasčiau -- nereikia kvaršinti galvos, ar jie priskirti tik vienam, ar keliems kintamiesiems, kaip kad reikėjo pavyzdyje su sąrašais.
Tik nekintamus objektus galima naudoti kaip žodynų raktus.