Python/Объектно-ориентированное программирование на Python: различия между версиями

Содержимое удалено Содержимое добавлено
оформление ВУ
Строка 2:
 
=== Принципы ООП ===
Согласно [[w:Кей, Алан|Алану Кэю]] — автору языка программирования [[w:Smalltalk|Smalltalk]] — объектно-ориентированным может называться язык, построенный с учетом следующих принципов<ref name="alan kay oop principles">[http://www.cs.aau.dk/~torp/Teaching/E02/OOP/handouts/introduction.pdf Introduction to Object-Oriented Programming]</ref>:
 
* Все данные представляются объектами
Строка 13:
 
=== Определение класса ===
Для определения [[w:Класс (программирование)|класса]] используется оператор <code>class</code>:
<source lang="python">
class имя_класса(надкласс1, надкласс2, ...):
Строка 25:
pass
</source>
В терминологии Python члены класса называются атрибутами, функции класса — [[w:Метод (программирование)|методами]], а [[w:Поле класса|поля класса]] — [[w:Свойство (программирование)|свойствами]] (или просто атрибутами).
 
Определения методов аналогичны определениям функций, но (за некоторыми исключениями, о которых ниже) методы всегда имеют первый аргумент, называемый по общепринятому соглашению <code>self</code>:
Строка 33:
# блок кода метода
</source>
Определения [[w:Атрибут (программирование)|атрибутов]] — обычные операторы присваивания, которые связывают некоторые значения с именами атрибутов.
<source lang="python">
class A:
Строка 51:
 
=== Создание экземпляра ===
Для создания [[w:Объект (программирование)|объекта]] — экземпляра класса (то есть, инстанцирования класса), достаточно вызвать класс по имени и задать параметры конструктора:
<source lang="python">
class Point:
Строка 67:
</source>
 
Переопределив классовый метод <code>__new__</code>, можно управлять процессом создания экземпляра. Этот метод вызывается до метода <code>__init__</code> и должен вернуть новый экземпляр либо <code>None</code> (в последнем случае будет вызван <code>__new__</code> родительского класса). Метод <code>__new__</code> используется для управления созданием неизменчивых (immutable) объектов, управления созданием объектов в случаях, когда <code>__init__</code> не вызывается, например, при десериализации (unpickle). Следующий код демонстрирует один из вариантов реализации [[w:Одиночка (шаблон проектирования)|шаблона Одиночка]]:
<source lang="python">
>>> class Singleton(object):
Строка 113:
Обычно время жизни объекта, определённого в программе на Python, не выходит за рамки времени выполнения процесса этой программы.
 
Для преодоления этого ограничения объект можно сохранить, а после — восстановить. Как правило, при записи объекта производится его [[w:сериализация|сериализация]], а при чтении — десериализация.
 
<source lang="python">
Строка 128:
 
=== Инкапсуляция и доступ к свойствам ===
[[w:Инкапсуляция (программирование)|Инкапсуляция]] является одним из ключевых понятий ООП. Все значения в Python являются объектами, инкапсулирующими код (методы) и данные и предоставляющими пользователям общедоступный интерфейс. Методы и данные объекта доступны через его атрибуты.
 
Сокрытие информации о внутреннем устройстве объекта выполняется в Python на уровне соглашения между программистами о том, какие атрибуты относятся к общедоступному интерфейсу класса, а какие — к его внутренней реализации. Одиночное подчеркивание в начале имени атрибута говорит о том, что атрибут не предназначен для использования вне методов класса (или вне функций и классов модуля), однако, атрибут все-таки доступен по этому имени. Два подчеркивания в начале имени дают несколько большую защиту: атрибут перестает быть доступен по этому имени. Последнее используется достаточно редко.
 
Есть существенное отличие между такими атрибутами и личными (private) членами класса в таких языках как [[w:C++|C++]] или [[w:Java|Java]]: атрибут остается доступным, но под именем вида <code>_ИмяКласса__ИмяАтрибута</code>, а при каждом обращении <code>Python</code> будет модифицировать имя в зависимости от того, через экземпляр какого класса происходит обращение к атрибуту. Таким образом, родительский и дочерний классы могут иметь атрибут с именем, например, «__f», но не будут мешать друг другу.
<source lang="python">
>>> class parent(object):
Строка 195:
Существуют два способа централизованно контролировать доступ к атрибутам. Первый основан на перегрузке методов <code>__getattr__()</code>, <code>__setattr__()</code>, <code>__delattr__()</code>, а второй — метода <code>__getattribute__()</code> . Второй метод помогает управлять чтением уже существующих атрибутов.
 
Эти способы позволяют организовать полностью динамический доступ к атрибутам объекта или, что используется очень часто, имитации несуществующих атрибутов. По такому принципу функционируют, например, все системы [[w:Remote Procedure Call|RPC]] для Python, имитируя методы и свойства, реально существующие на удаленном сервере.
 
=== Полиморфизм ===
В компилируемых языках программирования [[w:Полиморфизм (программирование)|полиморфизм]] достигается
за счёт создания виртуальных методов, которые в отличие от невиртуальных можно перегрузить в
потомке. В Python все методы являются виртуальными, что является естественным
Строка 246:
</source>
 
Или, с использованием [[w:Python#Декораторы|декоратора]], так:
 
<source lang="python">
Строка 275:
Однако, в этом случае никакие преобразования типов не делаются, поэтому забота о согласованности данных
всецело лежит на программисте. Кроме того, присваивание атрибуту <code>__class__</code> не должно применяться по поводу и без. Прежде чем решиться на
его использование, необходимо рассмотреть менее радикальные варианты реализации изменения объекта, то есть по сути шаблона проектирования [[w:Состояние (шаблон проектирования)|State]].
 
Более того, полиморфизм в Python вообще не связан с наследованием, поэтому его можно считать сигнатурно-ориентированным полиморфизмом (signature-oriented polymorphism)<ref name="signature-oriented polymorfism">[http://lwn.net/2001/1011/a/python-url.php3 в списке рассылки comp.lang.python]</ref>. Например, чтобы экземпляру класса «прикинуться» файловым объектом, ему достаточно реализовать методы, относящиеся к файлам (обычно <code>.read()</code>, <code>.readlines()</code>, <code>.close()</code> и т. п.).
Строка 350:
 
=== Наследование и множественное наследование ===
При описании предметной области классы могут образовывать иерархию, в корне которой стоит базовый класс, а нижележащие классы (подклассы) наследуют свои атрибуты, уточняя и расширяя поведение вышележащего класса (надкласса). Обычно принципом построения классификации является отношение «IS-A» («есть» — между экземпляром и классом) и «AKO» («a kind of» — «разновидность» — между классом и суперклассом)<ref>[[w:Семантическая сеть#История|«AKO» и «IS-A»]]</ref>.
 
Python поддерживает как одиночное [[w:наследование (программирование)|наследование]], так и множественное, позволяющее классу быть производным от любого количества базовых классов.
 
<source lang="python">
Строка 366:
</source>
 
В Python (из-за [[w:утиная типизация|«утиной типизации»]]) отсутствие наследования
ещё не означает, что объект не может предоставлять тот же самый интерфейс.
 
[[w:Множественное наследование|Множественное наследование]] в Python применяется в основном для добавления примесей (mixins) — специальных классов, вносящих некоторую черту поведения или набор свойств{{sfn|Beazley|2009|pages=122}}.
 
==== Порядок разрешения доступа к методам и полям ====
За достаточно простым в использовании механизмом доступа к атрибутам в [[w:Python]] кроется довольно сложный алгоритм. Далее будет приведена последовательность действий, производимых интерпретатором при разрешении запроса <code>object.field</code> (поиск прекращается после первого успешно завершённого шага, иначе происходит переход к следующему шагу).
 
# Если у <code>object</code> есть метод <code>__getattribute__</code>, то будет вызван он с параметром <code>'field'</code> (либо <code>__setattr__</code> или <code>__delattr__</code> в зависимости от действия над атрибутом)
Строка 398:
переработана и дополнена. Однако для совместимости со старыми версиями
Python было решено сделать две объектные модели: «классические» типы (полностью совместимые
со старым кодом) и «новые»<ref name="python new style classes">[http://docs.python.org/reference/datamodel.html#new-style-and-classic-classes New-style Classes]</ref>. В версии [[w:Python3000|Python3000]] поддержка «старых» классов будет удалена.<br />
Для построения «нового» класса достаточно унаследовать его от другого
«нового». Если нужно создать «чистый» класс, то можно унаследоваться от <code>object</code> — родительского типа для всех «новых» классов.
Строка 408:
 
=== Агрегация. Контейнеры. Итераторы ===
Агрегация, когда один объект входит в состав другого, или отношение «HAS-A» («имеет»), реализуется в Python с помощью ссылок. Python имеет несколько встроенных типов [[w:Контейнер (программирование)|контейнеров]]: список, словарь, множество. Можно определить собственные классы контейнеров со своей логикой доступа к хранимым объектам. (Следует заметить, что в Python агрегацию можно считать разновидностью ассоциации, так реально объекты не вложены друг в друга в памяти и, более того, время жизни элемента может не зависеть от времени жизни контейнера.)
 
Следующий класс из модуля utils.py среды [http://webpy.org web.py] является примером контейнера-словаря, дополненного возможностью доступа к значениям при помощи синтаксиса доступа к атрибутам:
Строка 446:
</source>
 
Для доступа к контейнерам очень удобно использовать [[w:Итератор (программирование)|итераторы]]:
 
<source lang="python">
Строка 459:
 
=== Ассоциация и слабые ссылки ===
Отношение использования («USE-A») экземпляров одного класса другими является достаточно общим отношением. При использовании один класс обычно зависит от интерфейса другого класса (хотя эта зависимость может быть и взаимной). Если один объект использует другой, он обязательно содержит ссылку на него. Объекты могут ссылаться и друг на друга. В этом случае возникают [[w:Циклическая ссылка|циклические ссылки]]. Если ссылающиеся друг на друга объекты удалить, то они уже не могут быть удалены интерпретатором Python с помощью механизма подсчета ссылок. Удалением таких объектов занимается [[w:Сборка мусора (программирование)|сборщик мусора]].
 
Ассоциацию объектов без присущих ссылкам проблем можно осуществить с помощью ''слабых ссылок''. Слабые ссылки не препятствуют удалению объекта.
Строка 501:
 
=== Статический метод ===
[[w:Метод (программирование)|Статические методы]] в Python являются синтаксическими аналогами статических функций
в основных языках программирования. Они не получают ни экземпляр (<code>self</code>),
ни класс (<code>cls</code>) первым параметром.
Для создания статического метода (только [[w:Объектно-ориентированное программирование на Python#«Новые» и «классические» классы|«новые»]] классы могут иметь статические методы) используется [[w:Python#Декораторы|декоратор]] <code>staticmethod</code>
 
<source lang="python">
Строка 520:
 
Статические методы реализованы с помощью
[[w:Объектно-ориентированное программирование на Python#Инкапсуляция и доступ к свойствам|свойств (property)]].
 
=== Метод класса ===
Строка 528:
методы передается класс. Возможность создания классовых методов является
одним из следствий того, что в Python классы также являются объектами.
Для создания классового (только [[w:Объектно-ориентированное программирование на Python#"Новые" и "классические" классы|«новые»]] классы могут иметь классовые методы) метода можно использовать
декоратор <code>classmethod</code>
 
Строка 551:
Классовые методы достаточно часто используются для перегрузки конструктора.
Классовые методы, как и статические, реализуются через
[[w:Объектно-ориентированное программирование на Python#Инкапсуляция и доступ к свойствам|свойства (property)]].
 
=== Мультиметоды ===
Примером для иллюстрации сути [[w:мультиметод|мультиметод]]а может служить функция <code>add()</code> из модуля <code>operator</code>:
 
<source lang="python">
Строка 562:
</source>
 
В языке [[w:Python|Python]] достаточно легко реализовать и определённые пользователем мультиметоды<ref name="python multimethods">[http://www.ibm.com/developerworks/linux/library/l-pydisp.html Charming Python: Multiple dispatch]</ref>. Например, эмулировать мультиметоды можно с помощью модуля [http://gnosis.cx/download/gnosis/magic/multimethods.py multimethods.py] (из Gnosis Utils) :
<source lang="python">
from multimethods import Dispatch
Строка 589:
Объекты всегда имеют своё представление в памяти компьютера и их время жизни не больше времени работы программы. Однако зачастую необходимо сохранять данные между запусками приложения и/или
передавать их на другие компьютеры.
<!-- важные с точки зрения логики приложения объекты можно хранить и передавать. -->Одним из решений этой проблемы является устойчивость объектов ({{lang-en|object persistence}}) которая достигается с помощью хранения представлений объектов ([[w:Сериализация|сериализацией]]) в виде байтовых последовательностей и их последующего восстановления (десериализация).
 
Модуль <code>pickle</code> является наиболее простым способом «консервирования» объектов в Python.
Строка 637:
== Литература ==
* {{книга|автор=David M. Beazley|заглавие=Python Essential Reference|издание=4th Edition|год=2009|издательство=Addison-Wesley Professional|страниц=717|isbn=978-0672329784|ref=Beazley}}
{{BookCat}}
 
[[Категория:Python (язык программирования)]]