Об'єктно-орієнтоване програмування на Python: класи, опис і особливості
В Python класи є фундаментальним поняттям. Це основа стандартної бібліотеки, роботи більшості популярних програм і самої мови. Якщо ви хочете стати більше, ніж просто початківцям програмістом, ви повинні розуміти суть і принцип роботи з класами та об'єктами.
Об'єктно-орієнтоване програмування на Python повністю базується на ієрархічному спадкування класів. Це універсальний спосіб адаптації та багаторазового використання коду. Але об'єктно-орієнтований підхід не є обов'язковим. Python без проблем допускає виключно процедурне та функціональне програмування. Головне завдання класів у Python – упаковка даних і виконуваного коду. Синтаксично вони схожі на інструкції def. Подібно функцій, вони створюють свої простори імен, які можна неодноразово викликати з будь-якої частини програми. Навіщо ж тоді вони потрібні? Класи – це більш потужний і універсальний інструмент. Найбільше їх потенціал розкривається у момент створення нових об'єктів.
Завдяки спадкуванню, створюється дерево ієрархії. На практиці це виглядає наступним чином. Коли інтерпретатор зустрічає вираз object.attribute, він починає шукати перше входження attribute у зазначеному class. Не виявивши attribute, інтерпретатор продовжує пошук у всіх пов'язаних класах, які перебувають в дереві вище, у напрямку зліва направо. У древо пошуку входять: суперклассы, які знаходяться на самому верху ієрархії і реалізують загальну поведінку; підкласи – знаходяться нижче; примірники – елементи програми з успадкованим поведінкою. На малюнку зображено дерево класів Python. З прикладу видно, що Class 2 і 3 – це суперклассы. В самому низу знаходяться два примірники Instance 1 і 2 в середині – підклас Class 1. Якщо написати вираз Instance2.w, воно змусить інтерпретатор шукати значення атрибута .w в наступному порядку: Instance2; Class1; Class2; Class3. Ім'я .w ,буде знайдено в суперклассе Class3. На термінології ООП – це означає, що Instance 2 «успадковує» атрибут .w від Class3. Зверніть увагу, що примірники на малюнку успадковують тільки чотири атрибути: .w, .x, .y .z: Для примірників Instance1.x і Instance2.x атрибут .x буде знайдений Class 1 де пошук зупиниться, тому що Class 1 знаходиться в дереві нижче, ніж Class 2. Для Instance1.y і Instance2.y атрибут .y буде знайдений Class 1 де пошук зупиниться, тому що це єдине місце, де він з'являється. Для примірників Instance1.z і Instance2.z інтерпретатор знайде .z Class 2 тому що він розташовується в дереві лівіше, ніж Class3. Для Instance2.атрибут name .name буде знайдений в Instance2 без пошуку по дереву. Передостанній пункт є найбільш важливим. Він демонструє, як Class 1 перевизначає атрибут .x, заміщаючи версію .x суперкласу Class 2.
Що таке класи
Це базовий програмний компонент ООП. В Python класи використовуються для реалізації нових типів об'єктів і створюються за допомогою спеціальної інструкції class. Зовні вони нагадують стандартні вбудовані види даних, такі як числа або послідовності. Але у об'єктів класу є суттєва відмінність – підтримка спадкування.Об'єктно-орієнтоване програмування на Python повністю базується на ієрархічному спадкування класів. Це універсальний спосіб адаптації та багаторазового використання коду. Але об'єктно-орієнтований підхід не є обов'язковим. Python без проблем допускає виключно процедурне та функціональне програмування. Головне завдання класів у Python – упаковка даних і виконуваного коду. Синтаксично вони схожі на інструкції def. Подібно функцій, вони створюють свої простори імен, які можна неодноразово викликати з будь-якої частини програми. Навіщо ж тоді вони потрібні? Класи – це більш потужний і універсальний інструмент. Найбільше їх потенціал розкривається у момент створення нових об'єктів.
Важливість класів і принцип успадкування
У кожного об'єкта є свій простір імен, яке можна програмувати, вводити змінні і створювати будь-які функції. А також є атрибути, успадковані від класу object.attribute. У цьому полягає сенс ООП.Завдяки спадкуванню, створюється дерево ієрархії. На практиці це виглядає наступним чином. Коли інтерпретатор зустрічає вираз object.attribute, він починає шукати перше входження attribute у зазначеному class. Не виявивши attribute, інтерпретатор продовжує пошук у всіх пов'язаних класах, які перебувають в дереві вище, у напрямку зліва направо. У древо пошуку входять: суперклассы, які знаходяться на самому верху ієрархії і реалізують загальну поведінку; підкласи – знаходяться нижче; примірники – елементи програми з успадкованим поведінкою. На малюнку зображено дерево класів Python. З прикладу видно, що Class 2 і 3 – це суперклассы. В самому низу знаходяться два примірники Instance 1 і 2 в середині – підклас Class 1. Якщо написати вираз Instance2.w, воно змусить інтерпретатор шукати значення атрибута .w в наступному порядку: Instance2; Class1; Class2; Class3. Ім'я .w ,буде знайдено в суперклассе Class3. На термінології ООП – це означає, що Instance 2 «успадковує» атрибут .w від Class3. Зверніть увагу, що примірники на малюнку успадковують тільки чотири атрибути: .w, .x, .y .z: Для примірників Instance1.x і Instance2.x атрибут .x буде знайдений Class 1 де пошук зупиниться, тому що Class 1 знаходиться в дереві нижче, ніж Class 2. Для Instance1.y і Instance2.y атрибут .y буде знайдений Class 1 де пошук зупиниться, тому що це єдине місце, де він з'являється. Для примірників Instance1.z і Instance2.z інтерпретатор знайде .z Class 2 тому що він розташовується в дереві лівіше, ніж Class3. Для Instance2.атрибут name .name буде знайдений в Instance2 без пошуку по дереву. Передостанній пункт є найбільш важливим. Він демонструє, як Class 1 перевизначає атрибут .x, заміщаючи версію .x суперкласу Class 2.
Об'єкти, примірники і методи
ООП оперує двома головними поняттями: класи і об'єкти. Класи створюють нові типи, а об'єкти класів в Python є їх екземплярами. Наприклад, всі цілочисельні змінні відносяться до інтегрованого типу даних int. На мові ООП вони є екземплярами класу int. Класи створюються інструкціями, а об'єкти з допомогою викликів. Вони можуть зберігати дані і володіти своїм функціоналом або методами класів. В Python термінологія відіграє важливу роль. З її допомогою програмісти відрізняють незалежні функції від тих, що належать класів. Змінні, що відносяться до об'єктів, називають полями. Розрізняють два види полів в ООП. Перший – це змінні, що належать цілого класу, другий – змінні окремих екземплярів. Поля і методи разом є атрибутами класу. В Python вони записуються в блоці коду після ключового слова class.Методи та значення self
Методи – це функції з додатковим ім'ям self. Воно додається до початку списку параметрів. При бажанні змінну можна назвати іншим ім'ям, але така ініціатива серед програмістів не вітається. Self – це стандартне, легко впізнаване в коді ім'я. Тим більше на роботу з ним розраховані деякі середовища розробки. Щоб краще зрозуміти значення self в ООП, уявімо, що у нас є клас з ім'ям ClassA і методом methodA: class ClassA; def methodA (self, аргумент1 аргумент2). Об'єкт objectA є екземпляром ClassA і виклик методу виглядає наступним чином: objectA.methodA(аргумент1 аргумент2). Коли інтерпретатор бачить цю сходинку, він автоматично перетворює наступним чином: ClassA.methodA(objectA, аргумент1 аргумент2). Тобто екземпляр класу використовує змінну self як посилання на самого себе.Як створювати змінні, методи і екземпляри класів
Пропонуємо розібрати практичний приклад з інтерактивної оболонки Python. Створення класу «ЭкспериментПервый» починається з складовою інструкції class: class ЭкспериментПервый: def setinf(self, значення): #створюємо метод перший з аргументами self.data = значення def display(self): #метод другий print(self.data) #надрукувати дані примірника. Після обов'язкового відступу слід блок з вкладеними інструкціями def, в яких об'єктах функцій присвоюються імена setinf і display. З їх допомогою створюються атрибути ЭкспериментПервый.setinf і ЭкспериментПервый.display. Фактично будь-яке ім'я, яким присвоюється значення на верхньому рівні у вкладеному блоці, стає атрибутом. Щоб побачити, як працюють методи, необхідно створити два примірники: x = ЭкспериментПервый () # Створюються два примірники; y = ЭкспериментПервый () # Кожен є окремим простором імен. Спочатку екземпляри не зберігають ніякої інформації і абсолютно порожні. Але вони пов'язані зі своїм класом: x.setinf(«Вчимо Пітон») #Виклик методу, в якому self – x. y.setinf(314) #Еквівалентно: ЭкспериментПервый.setinf(y, 314) Якщо через ім'я примірників x, y звернутися до атрибуту .setinf об'єкта класу ЭкспериментПервый, то в результаті пошуку по дереву спадкування інтерпретатор повертає значення атрибута класу. x.display() #У x і y свої значення self.data Вчимо Пітон y.display() 314.Перевантаження операторів
В мові Python класи можуть перевантажувати оператори виразів. Така можливість робить примірники схожими на вбудовані типи даних. Процес полягає в реалізації методів зі спеціальними іменами, що починаються і закінчуються подвійним підкресленням. Розглянемо в дії __init__ і __sub__. Перший метод називають конструктором класу. В Python __init__ виконує перевантаження операції створення екземплярів. Другий метод __sub__ реалізує операцію віднімання. class Перевантаження: #створюється новий клас def __init__(self, start): self.data = start def __sub__(self, other): # примірник мінус other return Перевантаження(self.data - other) #Результатом буде новий примірник A = Перевантаження(10) #__init__(A, 10) B = A – 2 #__sub__(B, 2) B. data #B – це новий екземпляр класу Перевантаження 8.Детальніше про метод __init__
Метод __init__ найчастіше використовується при роботі з класами. Він незамінний для ініціалізації різних об'єктів. __init__ окремо викликати. При створенні нового примірника метод автоматично отримує аргументи, зазначені в дужках. За допомогою методів перевантаження можна реалізувати будь-які операції з вбудованими типами даних. Більшість використовуються тільки при вирішенні спеціальних завдань, в яких необхідно, щоб об'єкти імітували поведінку стандартних об'єктів. Методи успадковуються від суперклассов і не є обов'язковими. На початкових етапах можна легко без них обійтися. Але для повного занурення в програмування і суть ООП потрібен навик роботи з операторами.Метод __getitem__
Метод __getitem__ виконує перевантаження доступу до елемента з індексом. Якщо він успадковується або присутній у визначенні класу, то при кожній операції індексування інтерпретатор буде викликати його автоматично. Наприклад, коли примірник F з'являється у виразі вилучення елемента з індексом, такому як F[i], інтерпретатор Python викликає метод __getitem__, передає об'єкт F в першому аргументі індекс, вказаний у квадратних дужках, у другому. Наступний клас «ПримерИндексации» повертає квадрат значення індексу: class ПримерИндексации: def __getitem__(self, index): return index ** 2 F = ПримерИндексации () F[2]#Вираз F[i]викликає F.__getitem__(i) 4 for i in range(5): print(F[i], end=« ») # Викликає __getitem__(F, i) в кожній ітерації 014 916 З допомогою цього методу можна виконати операцію вилучення зрізу, до якої часто вдаються під час роботи з послідовностями. При обробці списків стандартний синтаксис операції виглядає наступним чином: Список =[13, 6, «и», «с», 74,9] Список[2:4] [«и», «с»] Список[1:] [6, «и», «с», 74,9] Список[:-1] [13, 6, «и», «с»] Список[::2] [13, «и», 74,9] Клас, що реалізує метод __getitem__: class Індексатор: мой_список =[13, 6, «и», «с», 74,9] def __getitem__(self, індекс): #Викликається при індексуванні або витягу зрізу print(«getitem: », індекс) return self.мой_список[индекс]#Виконує індексування або витягує зріз X = Індексатор() X[0]#При індексуванні __getitem__ отримує ціле число getitem: 0 13 X[2:4]# При витяганні зрізу __getitem__ отримує об'єкт зрізу getitem: slice(2 4 None) [«и», «с»]Звернення до атрибутів
Для отримання посилання на атрибут використовується спеціальний метод __getattr__. Він викликається з ім'ям атрибута у вигляді рядка у випадках виявлення спроби отримати посилання на неіснуючий або невизначений атрибут. Коли інтерпретатор може виявити шуканий об'єкт в дереві спадкування, __getattr__.не викликається. Метод зручний для узагальненої обробки запитів до атрибутів: class Gone: def __getattr__(self, atname): if atname == «age»: return 20 else: raise AttributeError, atname D = Gone() D. age 20 D. name AttributeError: name У класу Gone та його примірника D своїх атрибутів немає. Тому при зверненні до D. age автоматично викликається метод __getattr__. Сам примірник передається як self, а ім'я невизначеного «age» в рядку atname. Клас повертає результат звернення до імені D. age, незважаючи на те, що даного атрибуту у нього немає. Якщо класом не передбачається обробка атрибута, метод __getattr__ викликає вбудоване виняток, і тим самим передає інтерпретатору інформацію про те, що ім'я в дійсності є невизначеним. В даному випадку спроба звернутися до імені D. name призводить до появи помилки. Аналогічним чином працює метод перевантаження операторів __setattr__, перехоплюючи кожну спробу привласнити значення атрибуту. Якщо цей метод прописаний в тілі класу, вираз «self.атрибут = значення» буде перетворено на виклик методу self.__setattr_(«атрибут», значення). Ми описали лише декілька з існуючих методів перевантаження. Весь перелік знаходиться у стандартному керівництві мови і містить набагато більше імен.Додаткові можливості
ООП іноді використовують для складних і нестандартних завдань. Завдяки успадкування класів в Python, поведінка вбудованих типів даних та їх можливості піддаються розширенню та адаптації. Якщо вас не влаштовує той факт, що індексація в послідовностях починається з нуля, ви можете це виправити за допомогою інструкції class. Для цього потрібно створити підклас типу list з новими іменами всіх типів і реалізувати необхідні зміни. Також в ООП на мові Python існують декоратори функцій, статичні методи і безліч інших складних і спеціальних прийомів.Схожі статті
Умовні інструкції if/else в Python: синтаксис і застосування
Мова програмування Python містить потужний набір процедурних інструкцій. Вони необхідні для обробки окремих об'єктів і великих блоків коду,
Який вибрати мову програмування: Java або Python?
Кожна людина, яка бажає навчитися програмуванню або просто вивчити нову мову, стикається з двома великими мовами: Java і Python. Це дійсно дуже
Об'єктно-орієнтовані мови. Основи об'єктно-орієнтованого програмування
Мови об'єктно-орієнтованого програмування побудовані на концепції, що в основі їх лежить поняття об'єкта. Об'єкт - це сутність, яка