Основи об’єктно-орієнтованого програмування в Python |
Написав Invader | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Неділя, 04 серпня 2013 12:39 Переглядів: 21965
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Python ua: Об’єктно-орієнтоване програмуванняВступВсі програми, які ми писали до цього були побудовані навколо функцій — блоків інструкцій, які маніпулюють даними. Такий підхід до створення програм називається процедурним програмуванням. Існує інший спосіб організації програмного коду, який об’єднує дані і функціональність всередині сутності, яку називають об’єктом. Це називається об’єктно-орієнтованою парадигмою програмування. Більшість часу ти можеш використовувати процедурне програмування, але при написанні великих програм краще використовувати саме цей підхід. Класи і об’єкти — два головних аспекти ООП. Клас створює новий тип, тим часом як об’єкти — це екземпляри класу. За аналогією можна сказати, що змінна типу int є екземпляром (об’єктом) класу int.
Зауваження для програмістів на статично-типізованих мовах Навіть змінні цілочислового типу вважаються об’єктами (класу int). На відміну від C++ і Java (до версії 1.5) де цілі числа — примітивний тип. Див. help(int).
Об’єкти можуть зберігати в собі якісь дані, використовуючи звичайні змінні, які належать об’єкту. Змінні, які належать об’єкту або класу також називаються полями. Використовуючи функції, які належать класу, об’єкти отримують певну функціональність. Такі функції наз. методами класу. Ця термінологія важлива, тому що вона допомагає розрізняти незалежні функції і змінні і ті що є частиною об’єкту або класу. Поля і методи також можна назвати атрибутами класу. Поля поділяються на два типи — вони можуть належати кожному екземпляру/об’єкту класу або лише самому класу. Вони називаються змінними об’єкту і змінними класу відповідно. Клас створюється за допомогою ключового слова class. Поля і методи класу перераховуються всередині блоку.
selfМетоди класу мають лише одну характерну відмінність від звичайних функцій — вони повинні мати додаткову змінну яка має бути додана до списку параметрів ПЕРШОЮ, але значення цього параметру ти не вказуєш, Python сам надасть його, коли метод буде викликано. Ця особлива змінна посилається на сам об’єкт, і за домовленістю, має назву self. Можна замінити self на щось інше, але краще цього не робити. Використання стандартного імені дає багато переваг — будь-хто без проблем розпізнає його, і навіть спеціалізовані IDE будуть тобі допомагати, якщо ти використовуєш self.
Зауваження для програмістів на C++/java/C# Ім’я self еквівалентно вказівнику this в C++ і посиланню this в Java і C#.
Напевно тебе дивує як Python надає значення змінній self і чому тобі не потрібно цього робити. Наступний приклад все прояснить. Отже, ти маєш клас MyClass і екземпляр цього класу, який називається myobject. Коли ти викликаєш метод цього об’єкту як myobject.method(arg1, arg2), виклик методу автоматично конвертується Python’ом в MyClass.method(myobject, arg1, arg2) — ось і все для чого self призначено. Це також означає, що для будь-якого методу є хоча б один аргумент — self. Якщо ж знайдеться метод без аргументів, то тобі все одно доведеться вказувати один. І це буде self.
КласиНайпростіший клас наведено нижче: Вивід:
Ми створили клас використовуючи інструкцію class. Після неї йде вкладений блок інструкцій який формує тіло класу. В даному випадку блок порожній на що вказує інструкція pass. Потім ми створили об’єкт/екземпляр цього класу, використовуючи ім’я класу, що розташоване перед парними дужками. Для нашої перевірки ми просто вивели на екран тип змінної. Перевірка показала, що у нас є екземпляр класу Person в модулі __main__. Зауваж, що адреса пам’яті комп’ютера, де зберігається об’єкт також виводиться на екран. На твоєму комп’ютері адреса може бути іншою, оскільки Python може зберегти об’єкт туди, де він знайде вільне місце.
Методи об’єктівМи вже обговорили те що класи і об’єкти можуть мати методи, які є звичайними функціями окрім, звичайно, змінної self. Зараз ми розберемо приклад: Виведе:
Як це працює? В цій програмі ми побачили змінну self в дії. Зауваж, що метод sayHi не приймає параметрів, але все одно має ім’я self у визначенні функції.
Метод __init__В Python’івських класах є багато методів, які мають спеціальне значення. Зараз ми побачимо яке значення має метод __init__. Метод __init__ виконується кожен раз, коли створюється екземпляр класу. Даний метод корисний, коли потрібно щось ініціалізувати. Зверни увагу на подвійне нижнє підкреслювання на початку і в кінці імені. Приклад: Вивід:
Як це працює: В цій програмі ми визначили метод __init__, який може приймати, крім параметру self, іще один — name. Всередині методу __init__ ми просто створили нове ім’я name. Зверни увагу на те, що це дві різні змінні не зважаючи на те, що вони називаються однаково. Крапкова нотація дозволяє нам розрізняти їх. Більш важливо те, що ми не викликаємо метод __init__ явно. Ми просто визначили функцію всередині класу. Після всього ми нарешті можемо використати поле self.name в наших методах. Як у випадку з методом sayHi.
Змінні класу і об’єктуМи вже поговорили про функціональну частину класів і об’єктів (методи), тепер же почнемо вивчати ту частину, що стосується даних. Дані, іншими словами поля, це не що інше як звичайні змінні обмежені простором імен класів і об’єктів. Це означає, що ці змінні є чинними лише в контексті цих класів і об’єктів. Ось чому це називається простором імен. Існує два типи полів — змінні класу і змінні об’єкту, які класифікуються на основі того класу чи об’єкту належить змінна. Змінні класу є спільними — до них можна отримати доступ з усіх екземплярів класу. Існує всього одна копія змінної даного типу і тому, коли один об’єкт змінює її, цю зміну побачать інші об’єкти. Змінні об’єкту не є спільними для всіх екземплярів класу і належать лише певному об’єкту. Кожен об’єкт має власну копію поля, навіть якщо назва поля в одному об’єкті співпадає з назвою поля в іншому. Наступний приклад допоможе краще це зрозуміти: Вивід:
Як це працює: Це довгий приклад, але він допоможе проілюструвати сутність змінних класів і об’єктів. Змінна population належить класу Robot і таким чином є змінною класу. Змінна name належить об’єкту (привласнена за допомогою self) і тому є змінною об’єкту. Отже, ми посилаємося на змінну класу population за доп. виразу Robot.population а не self.population. Але для доступу до змінної name,яка належить об’єкту, потрібно написати self.name всередині методу об’єкта. Запам’ятай цю просту відмінність між цими двома типами змінних. Також пам’ятай, що змінна об’єкту з тим же іменем що і змінна класу зробить недоступною (приховає) змінну класу! howMany насправді метод класу. Це означає, що ми можемо визначити його або як classmethod або як staticmethod в залежності від того чи потрібно нам знати частиною якого класу він є. Оскільки ця інформація нам непотрібна, то використаємо staticmethod. Ми б могли досягти того ж самого скориставшись декораторами (http://www.ibm.com/developerworks/linux/library/l-cpdecor.html): nЗауваж, що метод __init__ був використаний для створення екземпляру класу Robot і одночасно з цим наданням йому імені. В цьому методі ми збільшуємо змінну population на 1 кожен раз, коли викликається даний метод — кожен виклик це ще один робот. Значення self.name буде специфічним для кожного створеного нами об’єкту. Запам’ятай, що звертатися до змінних і методів об’єкту з яким в даний момент працюєш потрібно використовуючи змінну self. Це називається посиланням на атрибут. В цій програмі використані рядки документації (Коментарі обмежені 3 лапками). Ми можемо отримати доступ до рядків документації на рівні класу скориставшись конструкцією Robot.__doc__ і Robot.sayHi.__doc__ для документації, яка знаходиться в методі. Крім методу __init__ існує іще один спеціальний метод __del__, який викликається кожного разу, коли об’єкт знищується. Іншими словами, його більше не використовують і ту область пам’яті, яку він займав звільняють. Всередині цього методу ми просто зменшуємо змінну Robot.population на 1 кожного разу, коли видаляємо об’єкт класу Robot. Метод __del__ викликається тоді, коли об’єктом вже не користуються і зауваж, немає жодної гарантії коли саме це станеться. Можна і самостійно викликати цей метод виконавши інструкцію del для об’єкту. В такому випадку ми вручну знищимо об’єкт.
Зауваження для програмістів на C++, Java, C# В Python всі члени класу є публічними, а всі методи віртуальними.
Один виняток: імена з 2-ма символами підкреслення в якості префіксу, такі як, наприклад, __privatevar. Змінні з такими ідентифікаторами таки стають приватними.
Таким чином існує домовленість, про те що всі імена змінних, які будуть використовуватися тільки всередині класу чи об’єкту мають починатися із символу нижнього підкреслення, а всі інші імена публічні, і можуть використовуватися іншими класами/об’єктами. Запам’ятай, що це тільки домовленість і Python не примушує тебе слідувати їй (окрім подвійного нижнього підкреслення).
Наслідування (успадкування)Одна з головних вигод від використання ООП це повторне використання коду. І один із способів за допомогою якого це досягається полягає у використані механізму наслідування. Наслідування можна уявити як втілення відносин тип і підтип, між класами. Припустимо, що ти хочеш написати програму, яка має слідкувати за вчителями і учнями в коледжі. Вони всі мають певні спільні характеристики такі як ім’я, вік і адреса. Також є певні специфічні ознаки такі як зарплатня, курси і плани для вчителів і оцінки та збори для учнів. Ти можеш створити два незалежні класи для кожного типу, але додавання нової спільної характеристики буде означати додавання її до кожного класу з цих двох незалежних. Це швидко стане незручним. Кращим підходом буде створення спільного класу SchoolMember з подальшим наслідуванням від цього класу двох інших класів — учень і вчитель. Ці класи стануть підтипами типу (класу) SchoolMember. В подальшому можна буде додавати будь-які специфічні для цих класів характеристики. Цей метод має багато переваг. При додаванні/зміні функціональності класу SchoolMember зміни автоматично будуть відображені і у всіх його нащадках (підтипах, підкласах). Наприклад, можна додати до класу SchoolMember нове поле ID (ідентифікатор) картки, то підкласи вчитель і учень теж його отримають. Але зміни в підкласах не розповсюджуються на інші підкласи. Іншою перевагою є те що можна зіслатися на об’єкт вчитель або учень скориставшись об’єктом SchoolMember. Це може бути корисним в певних ситуаціях, коли наприклад, треба порахувати к-ть членів школи. Це називається поліморфізмом, коли підтип може, у будь-яких ситуаціях, в яких очікується використання батьківського типу, замістити собою цей самий батьківський тип. Іншими словами, об’єкт може бути опрацьований як примірник батьківського класу. Також зауваж, що ми повторно використали код головного класу і нам не потрібно повторювати його в інших класах як у випадку з незалежними класами. Клас SchoolMember в цій ситуації відомий як базовий клас або суперклас (надклас). Вчитель і учень — це похідні класи або підкласи. Зараз подивимося як це виглядає в програмному коді: Вивід:
Як це працює: Для використання наслідування ми вказали ім’я базового класу (від якого будемо наслідувати) в дужках які йдуть відразу після імені класу (як і при створенні функцій, лише з тією різницею, що в якості аргументу виступає назва базового класу). Приклад:
Далі відбувається виклик методу __init__ базового класу якому передається посилання на поточний екземпляр класу, тобто об’єкт (який буде створено в майбутньому). Це робиться для того, щоб ми могли ініціалізувати базовий клас як частину об’єкта. Дуже важливо запам’ятати, що Python автоматично не викликає конструктор базового класу, тобі потрібно самостійно викликати його. Зауваж, те як ми викликали метод базового класу з його підкласу:
Слід знати, що Python завжди починає з пошуку методів всередині поточного класу, якщо ж він не може знайти потрібного методу всередині підкласу, то починає шукати в базовому класі. В тому порядку в якому вони (методи) розташовані у визначенні класу. Якщо відбувається наслідування від декількох класів (більше ніж один клас перераховано в визначенні підкласу), то це називається множинним наслідуванням.
ПідсумокPython дуже об’єктно-орієнтована мова і добре розуміння концепцій ООП дуже тобі допоможе в довгостроковій перспективі.
Далі ми дізнаємося як працювати з файлами. Якщо у вас виникли питання або щось не зрозуміло - залишайте коментарі і ми дамо відповідь! ( 26 Проголосувало )
3.26 Copyright (C) 2008 Compojoom.com / Copyright (C) 2007 Alain Georgette / Copyright (C) 2006 Frantisek Hliva. All rights reserved." |