Language
Lt :: En

Lecture 2 (2004-09-13)

This page is only available in Lithuanian

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.


Valid XHTML 1.1! Valid CSS! Last updated: 2016-09-10