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

Содержимое удалено Содержимое добавлено
→‎Полиморфизм: орфографическая ошибка в слове polymorphism.
перенесено из Википедии
Строка 1:
{{К удалению|2017-01-08}}
'''Объектно-ориентированное программирование на Python''' — программирование на Python с использованием [[парадигма программирования|парадигмы]] [[объектно-ориентированное программирование|ООП]]: с самого начала [[Python]] проектировался как [[объектно-ориентированный язык программирования]]<ref name="python oop from beginning">[http://www.ercb.com/ddj/1997/ddj.9711.html Dr. Dobb’s Journal, November, 1997]</ref>.
 
== Введение ==
 
=== Принципы ООП ===
Согласно [[Кей, Алан|Алану Кэю]]  — автору языка программирования [[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>:
 
* Все данные представляются объектами
Строка 28 ⟶ 25 :
pass
</source>
В терминологии Python члены класса называются атрибутами, функции класса  — [[Метод (программирование)|методами]], а [[Поле класса|поля класса]]  — [[Свойство (программирование)|свойствами]] (или просто атрибутами).
 
Определения методов аналогичны определениям функций, но (за некоторыми исключениями, о которых ниже) методы всегда имеют первый аргумент, называемый по общепринятому соглашению <code>self</code>:
Строка 36 ⟶ 33 :
# блок кода метода
</source>
Определения [[Атрибут (программирование)|атрибутов]]  — обычные операторы присваивания, которые связывают некоторые значения с именами атрибутов.
<source lang="python">
class A:
Строка 54 ⟶ 51 :
 
=== Создание экземпляра ===
Для создания [[Объект (программирование)|объекта]]  — экземпляра класса (то есть, инстанцирования класса), достаточно вызвать класс по имени и задать параметры конструктора:
<source lang="python">
class Point:
Строка 116 ⟶ 113 :
Обычно время жизни объекта, определённого в программе на Python, не выходит за рамки времени выполнения процесса этой программы.
 
Для преодоления этого ограничения объект можно сохранить, а после  — восстановить. Как правило, при записи объекта производится его [[сериализация]], а при чтении  — десериализация.
 
<source lang="python">
Строка 133 ⟶ 130 :
[[Инкапсуляция (программирование)|Инкапсуляция]] является одним из ключевых понятий ООП. Все значения в Python являются объектами, инкапсулирующими код (методы) и данные и предоставляющими пользователям общедоступный интерфейс. Методы и данные объекта доступны через его атрибуты.
 
Сокрытие информации о внутреннем устройстве объекта выполняется в Python на уровне соглашения между программистами о том, какие атрибуты относятся к общедоступному интерфейсу класса, а какие  — к его внутренней реализации. Одиночное подчеркивание в начале имени атрибута говорит о том, что атрибут не предназначен для использования вне методов класса (или вне функций и классов модуля), однако, атрибут все-таки доступен по этому имени. Два подчеркивания в начале имени дают несколько большую защиту: атрибут перестает быть доступен по этому имени. Последнее используется достаточно редко.
 
Есть существенное отличие между такими атрибутами и личными (private) членами класса в таких языках как [[C++]] или [[Java]]: атрибут остается доступным, но под именем вида <code>_ИмяКласса__ИмяАтрибута</code>, а при каждом обращении <code>Python</code> будет модифицировать имя в зависимости от того, через экземпляр какого класса происходит обращение к атрибуту. Таким образом, родительский и дочерний классы могут иметь атрибут с именем, например, «__f», но не будут мешать друг другу.
Строка 196 ⟶ 193 :
Разумеется, первый способ хорош только если значение атрибута является атомарной операцией по изменению состояния объекта. Если же это не так, то второй способ позволит выполнить все необходимые действия в соответствующих методах.
 
Существуют два способа централизованно контролировать доступ к атрибутам. Первый основан на перегрузке методов <code>__getattr__()</code>, <code>__setattr__()</code>, <code>__delattr__()</code>, а второй  — метода <code>__getattribute__()</code> . Второй метод помогает управлять чтением уже существующих атрибутов.
 
Эти способы позволяют организовать полностью динамический доступ к атрибутам объекта или, что используется очень часто, имитации несуществующих атрибутов. По такому принципу функционируют, например, все системы [[Remote Procedure Call|RPC]] для Python, имитируя методы и свойства, реально существующие на удаленном сервере.
Строка 280 ⟶ 277 :
его использование, необходимо рассмотреть менее радикальные варианты реализации изменения объекта, то есть по сути шаблона проектирования [[Состояние (шаблон проектирования)|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> и  т.  п.).
 
=== Имитация встроенных типов ===
Встроенные типы и их методы имеют синтаксическую поддержку в языке Python или другие особые «привилегии». Конечно, любая операция может быть представлена синтаксисом вызова функции, однако, для частого применения это неудобно.
 
Воспользоваться точно такой же синтаксической поддержкой может и любой определённый пользователем класс. Для этого нужно лишь реализовать методы со специальными именами. Самый простой пример  — имитировать функцию:
<source lang="python">
>>> class Add:
Строка 335 ⟶ 332 :
</source>
 
Последний из методов  — <code>.__str__()</code>  — отвечает за представление экземпляра класса при печати оператором <code>print</code> и в других подобных случаях.
 
Аналогичные методы имеются и у соответствующих встроенных типов:
Строка 353 ⟶ 350 :
 
=== Наследование и множественное наследование ===
При описании предметной области классы могут образовывать иерархию, в корне которой стоит базовый класс, а нижележащие классы (подклассы) наследуют свои атрибуты, уточняя и расширяя поведение вышележащего класса (надкласса). Обычно принципом построения классификации является отношение «IS-A» («есть»  — между экземпляром и классом) и «AKO» («a kind of»  — «разновидность»  — между классом и суперклассом)<ref>[[Семантическая сеть#История|«AKO» и «IS-A»]]</ref>.
 
Python поддерживает как одиночное [[наследование (программирование)|наследование]], так и множественное, позволяющее классу быть производным от любого количества базовых классов.
Строка 372 ⟶ 369 :
ещё не означает, что объект не может предоставлять тот же самый интерфейс.
 
[[Множественное наследование]] в Python применяется в основном для добавления примесей (mixins)  — специальных классов, вносящих некоторую черту поведения или набор свойств{{sfn|Beazley|2009|pages=122}}.
 
==== Порядок разрешения доступа к методам и полям ====
Строка 403 ⟶ 400 :
со старым кодом) и «новые»<ref name="python new style classes">[http://docs.python.org/reference/datamodel.html#new-style-and-classic-classes New-style Classes]</ref>. В версии [[Python3000]] поддержка «старых» классов будет удалена.<br />
Для построения «нового» класса достаточно унаследовать его от другого
«нового». Если нужно создать «чистый» класс, то можно унаследоваться от <code>object</code>  — родительского типа для всех «новых» классов.
<source lang="python">
class OldStyleClass: pass # класс "старого" типа
class NewStyleClass(object): pass # и "нового"
</source>
Все стандартные классы  — классы «нового» типа.<ref>[http://www.python.org/download/releases/2.2.3/descrintro/ Объяснение Гвидо ван Россума об объединении типов и классов]</ref>
 
=== Агрегация. Контейнеры. Итераторы ===
Строка 469 ⟶ 466 :
 
=== Метаклассы ===
Обычных возможностей объектно-ориентированного программирования хватает далеко не всегда. В некоторых случаях требуется изменить сам характер системы классов: расширить язык новыми типами классов, изменить стиль взаимодействия между классами и окружением, добавить некоторые дополнительные аспекты, затрагивающие все используемые в приложении классы, и  т.  п.
 
При объявлении метакласса за основу можно взять класс <code>type</code>. Пример:
Строка 492 ⟶ 489 :
myobj = MySubObject("parameter")
</source>
Разумеется, вместо оператора <code>print</code> код метакласса может выполнять более полезные функции: регистрировать класс, передавать действия с классами на удаленную систему, использовать классы для других целей (например, как декларации или ограничения) и  т.  п.
 
== Методы ==
Строка 612 ⟶ 609 :
</source>
 
Получаемая при сериализации строка может быть передана по сети, записана в файл или специальное хранилище объектов, а позже  — прочитана. Сериализации поддаются не все объекты. Некоторые объекты (например, классы и функции) представляются своими именами, поэтому для десериализации требуется наличие тех же самых классов. Нужно отметить, что нельзя десериализовать данные из непроверенных
источников с помощью модуля <code>pickle</code>, так как при этом возможны практически любые
действия на локальной системе. При необходимости обмениваться данными по незащищенным каналам
или с ненадежными источниками можно воспользоваться другими модулями для сериализации.
 
В основе сериализации объекта стоит представление его состояния. По умолчанию состояние объекта  — это все, что записано в его полях. Пользовательские классы могут управлять сериализацией, предоставляя состояние объекта явным образом (методы <code>__getstate__</code>, <code>__setstate__</code> и др.).
 
На стандартном для Python механизме сериализации построена работа модуля <code>shelve</code> (shelve (англ. глаг.)  — ставить на полку; сдавать в архив). Модуль предоставляет функцию
<code>open</code>. Объект, который она возвращает, работает аналогично словарю, но объекты сериализуются и сохраняются в файле:
 
Строка 633 ⟶ 630 :
</source>
 
Сериализация <code>pickle</code>  — не единственная возможная, и подходит не всегда. Для сериализации, не зависящей от языка программирования, можно использовать, например, XML.
 
== Примечания ==
Строка 641 ⟶ 638 :
* {{книга|автор=David M. Beazley|заглавие=Python Essential Reference|издание=4th Edition|год=2009|издательство=Addison-Wesley Professional|страниц=717|isbn=978-0672329784|ref=Beazley}}
 
[[Категория:Python (язык программирования)]]
== Ссылки ==
 
{{rq|refless|renew}}
 
[[Категория:Объектно-ориентированное программирование]]
[[Категория:Python]]
[[Категория:Статьи с примерами кода Python]]