Чтение онлайн

на главную - закладки

Жанры

Язык программирования Python
Шрифт:

Еще один способ получить объект некоторого типа — использование функций–фабрик. По синтаксису вызов функции–фабрики не отличается от вызова конструктора класса.

Определение класса

Пусть в ходе анализа данной предметной области необходимо определить класс Граф. Граф — это множество вершин и набор ребер, попарно соединяющий эти вершины. Над графом можно проделывать операции, такие как добавление вершины, ребра, проверка наличия ребра в графе и т.п. На языке Python определение класса может выглядеть так:

Листинг

from sets import Set as set # тип для множества

class G:

def __init__(self, V, E):

self.vertices = set(V)

self.edges = set(E)

def add_vertex(self, v):

self.vertices.add(v)

def add_edge(self, (v1, v2)):

self.vertices.add(v1)

self.vertices.add(v2)

self.edges.add((v1, v2))

def has_edge(self, (v1, v2)):

return (v1, v2) in self.edges

def __str__(self):

return "%s; %s» % (self.vertices, self.edges)

Использовать

класс можно следующим образом:

Листинг

g = G([1, 2, 3, 4], [(1, 2), (2, 3), (2, 4)])

print g

g.add_vertex(5)

g.add_edge((5,6))

print g.has_edge((1,6))

print g

что даст в результате

Листинг

Set([1, 2, 3, 4]); Set([(2, 4), (1, 2), (2, 3)])

False

Set([1, 2, 3, 4, 5, 6]); Set([(2, 4), (1, 2), (5, 6), (2, 3)])

Как видно из предыдущего примера, определить класс не так уж сложно. Конструктор класса имеет специальное имя __init__. (Деструктор здесь не нужен, но он бы имел имя __del__.) Методы класса определяются в пространстве имен класса. В качестве первого формального аргумента метода принято использовать self. Кроме методов в объекте класса имеются два атрибута: vertices (вершины) и edges (ребра). Для представления объекта G в виде строки используется специальный метод __str__.

Принадлежность классу можно выяснить с помощью встроенной функции isinstance:

Листинг

print isinstance(g, G)

Инкапсуляция

Обычно считается, что без инкапсуляции невозможно представить себе ООП, что это ключевое понятие. История развития методологий программирования движима борьбой со сложностью разработки программного обеспечения. Сложность больших программных систем, в создании которых участвует сразу большое количество разработчиков, уменьшается, если на верхнем уровне не видно деталей реализации нижних уровней. Собственно, процедурный подход был первым шагом на этом пути. Под инкапсуляцией (incapsulation, что можно перевести по–разному, но на нужные ассоциации хорошо наводит слово «обволакивание») понимается сокрытие информации о внутреннем устройстве объекта, при котором работа с объектом может вестись только через его общедоступный (public) интерфейс. Таким образом, другие объекты не должны вмешиваться в «дела» объекта, кроме как используя вызовы методов.

В языке Python инкапсуляции не придается принципиального значения: ее соблюдение зависит от дисциплинированности программиста. В других языках программирования имеются определенные градации доступности методов объекта.

Доступ к свойствам

В языке Python не считается зазорным получить доступ к некоторому атрибуту (не методу) напрямую, если, конечно, этот атрибут описан в документации как часть интерфейса класса. Такие атрибуты

называются свойствами (properties). В других языках программирования принято для доступа к свойствам создавать специальные методы (вместо того чтобы напрямую обращаться к общедоступным членам–данным). В Python достаточно использовать ссылку на атрибут, если свойство ни на что в объекте не влияет (то есть другие объекты могут его произвольно менять). Если же свойство менее тривиально и требует каких–то действий в самом объекте, его можно описать как свойство (пример взят из документации к Python):

Листинг

class C(object):

def getx(self): return self.__x

def setx(self, value): self.__x = value

def delx(self): del self.__x

x = property(getx, setx, delx, «I'm the 'x' property.»)

Синтаксически доступ к свойству x будет обычной ссылкой на атрибут:

Листинг

>>> c = C

>>> c.x = 1

>>> print c.x

1

>>> del c.x

А на самом деле будут вызываться соответствующие методы: setx, getx, delx.

Следует отметить, что в экземпляре класса в Python можно организовать доступ к любым (даже несуществующим) атрибутам, обрабатывая запрос на доступ к атрибуту группой специальных методов:

__getattr__(self, name) Этот метод объекта вызывается в том случае, если атрибут не найден другим способом (его нет в данном экземпляре или в дереве классов). Здесь name — имя атрибута. Метод должен вычислить значение атрибута либо возбудить исключение AttributeError. Для получения полного контроля над атрибутами в «новых» классах (то есть потомках object) используйте метод __getattribute__.

__setattr__(self, name, value) Этот метод вызывается при присваивании значения некоторому атрибуту. В отличие от __getattr__, метод всегда вызывается, а не только тогда, когда атрибут может быть найден в экземпляре класса, поэтому нужно с осторожностью присваивать значения атрибутам внутри этого метода: это может вызвать рекурсию. Для присваивания значений атрибутов предпочтительнее присваивать словарю __dict__: self.__dict__[name] = value или (для «новых» классов) - обращение к __setattr__ базового класса: object.__setattr__(self, name, value).

__delattr__(self, name) Как можно догадаться из названия, этот метод служит для удаления атрибута.

Следующий небольшой пример демонстрирует все перечисленные моменты. В этом примере из словаря создается объект, именами атрибутов которого будут ключи словаря, а значениями — значения из словаря по заданным ключам:

Листинг

class AttDict(object):

def __init__(self, dict=None):

object.__setattr__(self, '_selfdict', dict or {})

def __getattr__(self, name):

if self._selfdict.has_key(name):

return self._selfdict[name]

else:

raise AttributeError

def __setattr__(self, name, value):

if name[0] != '_':

self._selfdict[name] = value

else:

raise AttributeError

def __delattr__(self, name):

if name[0] != '_' and self._selfdict.has_key(name):

del self._selfdict[name]

ad = AttDict({'a': 1, 'b': 10, 'c': '123'})

print ad.a, ad.b, ad.c

Поделиться:
Популярные книги

Тринадцатый XI

NikL
11. Видящий смерть
Фантастика:
попаданцы
аниме
фэнтези
фантастика: прочее
5.00
рейтинг книги
Тринадцатый XI

Хозяйка забытой усадьбы

Воронцова Александра
5. Королевская охота
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Хозяйка забытой усадьбы

Виконт. Книга 3. Знамена Легиона

Юллем Евгений
3. Псевдоним `Испанец`
Фантастика:
фэнтези
попаданцы
аниме
7.00
рейтинг книги
Виконт. Книга 3. Знамена Легиона

Шайтан Иван 6

Тен Эдуард
6. Шайтан Иван
Фантастика:
попаданцы
альтернативная история
историческое фэнтези
7.00
рейтинг книги
Шайтан Иван 6

Правильный лекарь. Том 12

Измайлов Сергей
12. Неправильный лекарь
Фантастика:
городское фэнтези
попаданцы
аниме
5.00
рейтинг книги
Правильный лекарь. Том 12

Последний рейд

Сай Ярослав
5. Медорфенов
Фантастика:
фэнтези
аниме
5.00
рейтинг книги
Последний рейд

Черный маг императора 3

Герда Александр
3. Черный маг императора
Фантастика:
попаданцы
аниме
5.00
рейтинг книги
Черный маг императора 3

Лихие. Авторитет

Вязовский Алексей
3. Бригадир
Фантастика:
альтернативная история
попаданцы
5.00
рейтинг книги
Лихие. Авторитет

Потомок бога

Решетов Евгений Валерьевич
1. Локки
Фантастика:
попаданцы
альтернативная история
аниме
сказочная фантастика
5.00
рейтинг книги
Потомок бога

Неудержимый. Книга XXX

Боярский Андрей
30. Неудержимый
Фантастика:
аниме
фэнтези
фантастика: прочее
попаданцы
5.00
рейтинг книги
Неудержимый. Книга XXX

Наследие Маозари 5

Панежин Евгений
5. Наследие Маозари
Фантастика:
фэнтези
юмористическое фэнтези
5.00
рейтинг книги
Наследие Маозари 5

Газлайтер. Том 3

Володин Григорий
3. История Телепата
Фантастика:
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Газлайтер. Том 3

Бастард Императора. Том 5

Орлов Андрей Юрьевич
5. Бастард Императора
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Бастард Императора. Том 5

Неудержимый. Книга XIX

Боярский Андрей
19. Неудержимый
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Неудержимый. Книга XIX