Search     or:     and:
 LINUX 
 Language 
 Kernel 
 Package 
 Book 
 Test 
 OS 
 Forum 
iakovlev.org

Python Tutorial 4


9. Классы

Классы в питоне - это смесь 2-х механизмов , взятых от C++ и Modula-3. Основные фичи - множественная наследование , перегрузка базовых методов .

Все члены класса , включая данные , имеют тип public, и все функции virtual. Нет специальных конструкторов или деструкторов . Классы сами по себе обьекты , в питоне все типы данных - обьекты. Встроенные операторы (напр,арифметические) имеют специфический синтаксис и могут быть переопределены для обьектов класса .

Обьекты индивидуальны . У одного обьекта может быть несколько имен (алиасов). Алиас - в некотором смысле указатель на обьект .

namespace - пространство имен обьектов . Примеры namespaces : встроенные имена (такие как функция abs()); глобальные имена модуля; локальные переменные функций . Между этими namespaces нет абсолютно никакой связи - например 2 разных модуля могут иметь 2 разных функции с одни и тем же названием``maximize''.

Термин attribute справедлив для любого имени , следующего за точкой - например в выражении z.real, real есть атрибут обьекта z. Ссылка на имя в модуле - ссылка на атрибут : в выражении modname.funcname, modname есть модуль и funcname - его атрибут .

Атрибуты могут быть на чтение или запись . Во втором случае возможна операция присваивания . Для атрибута модуля можно написать : "modname.the_answer = 42". Атрибут модуля может быть удален с помощью операции del . Например : "del modname.the_answer" .

Разные Namespaces создаются в разные моменты времени . Например , namespace для built-in имен создается в момент запуска интерпретатора Python . namespace для модуля создается в момент , когда читается его определение . Исполняемый код также имеет собственный глобальный namespace.

Локальный namespace для функции создается при ее вызове и удаляется при выходе . Хотя удаляется - это сказано круто , правильнее сказать - как-бы забывается и позднее будет ликвидирован сборщиком мусора .

scope - область видимости , в которой доступен namespace.

В любой момент времени доступны сразу несколько scopes : innermost scope - включает локальные имена и функции ; middle scope - глобальные имена текущего модуля; outermost scope - built-in идентификаторы .

Если имя глобально , оно лежит в middle scope . Все переменные за пределами innermost scope только на чтение .

Функция ищет глобальные переменные внутри своего модуля .

Операция присваивания в питоне выполняется всегда в innermost scope. Присваивание - это не копирование данных , это просто привязка имен к обьектам . То же справедливо и для удаления - операция "del x" удаляет привязку x .


9.3.1 Инициализация классов

Простейшая форма определения класса :

class ClassName:
     <statement-1>
     .
     .
     .
     <statement-N>
 

Класс можно определить в любом месте - хоть внутри функции .

Внутри класса идут определения функций .

Вместе с классом создается новый namespace .

Если внутри класса все определения корректны , создается обьект класса .


9.3.2 Обьект класса

Обьект класса может быть ссылкой или инстансом .

Ссылка стандартна для питона : obj.name. Например :

class MyClass:
     "A simple example class"
     i = 12345
     def f(self):
         return 'hello world'
 

После чего можно обратиться по ссылке MyClass.i и MyClass.f . К атрибутам класса можно применить операцию присваивания .

При создании инстанса используется функциональная нотация . При этом обьект класса есть параметризованная функция , которая возвращает обьект класса :

x = MyClass()
 

При этом создается пустой обьект . Класс может иметь специальный метод __init__():

    def __init__(self):
         self.data = []
 

При создании инстанса метод __init__() вызывается автоматом .

x = MyClass()
 

__init__() может иметь аргументы :

>>> class Complex:
 ...     def __init__(self, realpart, imagpart):
 ...         self.r = realpart
 ...         self.i = imagpart
 ...
 >>> x = Complex(3.0, -4.5)
 >>> x.r, x.i
 (3.0, -4.5)
 


9.3.3 Инстанс - обьекты .

В классах возможны 2 типа атрибутов - первый : data attributes. Это примерно то же самое , что и ``data members'' в C++. Например , если x - инстанс MyClass , следующий код распечатает 16:

x.counter = 1
 while x.counter < 10:
     x.counter = x.counter * 2
 print x.counter
 del x.counter
 

Второй тип атрибутов,который понимают инстансы,называется methods.

Любая функция класса может быть атрибутом-методом для инстанса . Например, x.f верная ссылка на метод, поскольку MyClass.f - функция, но x.i неверно, поскольку MyClass.i не существует. Но x.f - это не то же самое , что и MyClass.f -- это метод, а не функция.


9.3.4 Методы

Вызов метода :

x.f()
 

В нашем примере будет возвращена строка 'hello world'. Аналогично :

xf = x.f
 while True:
     print xf()
 

Внутри класса можно сделать ссылку на функцию , которая определена вне класса :

# Function defined outside the class
 def f1(self, x, y):
     return min(x, x+y)
 
 class C:
     f = f1
     def g(self):
         return 'hello world'
     h = g
 

Методы могут вызывать другие методы :

class Bag:
     def __init__(self):
         self.data = []
     def add(self, x):
         self.data.append(x)
     def addtwice(self, x):
         self.add(x)
         self.add(x)
 

Методы могут ссылаться на глобальные имена .


9.5 Наследование

Синтаксис для определения производного класса :

class DerivedClassName(BaseClassName):
     <statement-1>
     .
     .
     .
     <statement-N>
 

Должно быть определено имя базового класса BaseClassName. Можно также ссылаться на базовый класс из другого модуля .

class DerivedClassName(modname.BaseClassName):
 

Поведение производного класса аналогично базовому : если атрибут не найден в классе , он ищется в базовом классе .

Производный класс может перегружать методы базового класса .

Напрямую базовый класс можно вызвать так :"BaseClassName.methodname(self, arguments)".


9.5.1 Множественное наследование

Определение класса с множественным наследованием :

class DerivedClassName(Base1, Base2, Base3):
     <statement-1>
     .
     .
     .
     <statement-N>
 

При этом порядок наследования следующий : если атрибут не найден в DerivedClassName, он ищется в Base1, затем (рекурсивно) в базовом классе Base1, затем в Base2, и так далее . Для питона известна проблема , когда класс унаследован от 2-х классов , имеющих общий базовый класс .


9.6 Private переменные

Поддержка этого типа переменных специфична для питона . Такая переменная должна быть определена с префиксом _classname__spam, где classname имя класса. Тип private может быть как у данных , так и у методов .

Для создания типа , аналогичного типу``struct'' из C , можно использовать пустой класс :

class Employee:
     pass
 
 john = Employee() # Create an empty employee record
 
 # Fill the fields of the record
 john.name = 'John Doe'
 john.dept = 'computer lab'
 john.salary = 1000
 


9.8 Exceptions

Имеются 2 новых формы исключений :

raise Class, instance
 
 raise instance
 

В первом случае , instance должен быть инстансом Class или класса , производного от него . Второй вариант есть аналог для :

raise instance.__class__, instance
 

В следующем примере будет распечатано B, C, D :

class B:
     pass
 class C(B):
     pass
 class D(C):
     pass
 
 for c in [B, C, D]:
     try:
         raise c()
     except D:
         print "D"
     except C:
         print "C"
     except B:
         print "B"
 

Если поставить первым "except B" , будет напечатано B, B, B .


9.9 Итераторы

В любом контейнере можно использовать цикл с использованием for :

for element in [1, 2, 3]:
     print element
 for element in (1, 2, 3):
     print element
 for key in {'one':1, 'two':2}:
     print key
 for char in "123":
     print char
 for line in open("myfile.txt"):
     print line
 

У контейнера имеется 2 метода - iter() и next() . Их использование показано в примере :

>>> s = 'abc'
 >>> it = iter(s)
 >>> it
 <iterator object at 0x00A1DB50>
 >>> it.next()
 'a'
 >>> it.next()
 'b'
 >>> it.next()
 'c'
 >>> it.next()
 
 Traceback (most recent call last):
   File "<pyshell#6>", line 1, in -toplevel-
     it.next()
 StopIteration
 

Использование итераторов в классе :

class Reverse:
     "Iterator for looping over a sequence backwards"
     def __init__(self, data):
         self.data = data
         self.index = len(data)
     def __iter__(self):
         return self
     def next(self):
         if self.index == 0:
             raise StopIteration
         self.index = self.index - 1
         return self.data[self.index]
 
 >>> for char in Reverse('spam'):
 ...     print char
 ...
 m
 a
 p
 s
 


9.10 Генераторы

Генераторы - средство для создания итераторов . Используется ключевое слово yield , которое заменяет return :

def reverse(data):
     for index in range(len(data)-1, -1, -1):
         yield data[index]
 
 >>> for char in reverse('golf'):
 ...     print char
 ...
 f
 l
 o
 g
 

Генератор может быть выражением :

>>> sum(i*i for i in range(10))                 # sum of squares
 285
 
 >>> xvec = [10, 20, 30]
 >>> yvec = [7, 5, 3]
 >>> sum(x*y for x,y in zip(xvec, yvec))         # dot product
 260
 
 >>> from math import pi, sin
 >>> sine_table = dict((x, sin(x*pi/180)) for x in range(0, 91))
 
 >>> unique_words = set(word  for line in page  for word in line.split())
 
 >>> valedictorian = max((student.gpa, student.name) for student in graduates)
 
 >>> data = 'golf'
 >>> list(data[i] for i in range(len(data)-1,-1,-1))
 ['f', 'l', 'o', 'g']
 
Оставьте свой комментарий !

Ваше имя:
Комментарий:
Оба поля являются обязательными

 Автор  Комментарий к данной статье