Head First Python: трохи про класи. Абстракція поведінки і стану

  • 22 октября, 08:54
  • 3874
  • 0

У видавництві « Фабула» вийшла друком книжка Пола Беррі «Head First Python». Публікуємо уривок з неї.


Класи дозволяють зв’язати поведінку коду та його стан. У цьому розділі ми поки що залишимо у спокої вебзастосунок і почнемо вчитися створювати класи Python. Це вміння знадобиться вам при створенні диспетчера контексту. Класи є настільки корисною річчю, що вам у будь-якому разі варто ознайомитися з ними ближче, тому ми присвятили їм окремий розділ. Ми не будемо розглядати класи у всіх подробицях, а торкнемося лише тих аспектів, що стануть у пригоді при створенні диспетчера контексту, на який очікує наш вебзастосунок. Тож давайте подивимось, у чому тут справа…

Підключаємося до інструкції «with»

Як було зазначено наприкінці попереднього розділу, ви легко зможете підключити ініціалізуючий і завершальний код до інструкції with — якщо знаєте, як створити клас Python.

Незважаючи на те що половина книжки залишилася позаду, ви успішно подолали цей шлях, не оголосивши жодного класу. Ви написали корисний код, придатний для багаторазового використання, обмежившись лише механізмом функцій Python. Але існують інші способи організації коду, і об’єктно-орієнтований підхід дуже популярний.

Програмуючи на Python, ви не зобов’язані користуватися виключно об’єктно-орієнтованою парадигмою — ця мова має достатню гнучкість і дозволяє писати код у будь-якому стилі. Але коли йдеться про підключення до інструкції with, робити це рекомендується за допомогою класу, хоча стандартна бібліотека підтримує реалізацію схожої функціональності без класів (підхід, що використовується у стандартній бібліотеці, застосовується набагато рідше, тому ми не будемо його навіть розглядати).

Отже, для підключення до інструкції with слід створити клас. Коли ви дізнаєтеся, як писати класи, ви зможете створити свій клас і реалізувати в ньому підтримку протоколу управління контекстом. Цей протокол і є механізмом (вбудованим у Python) підключення до інструкції with.

Подивимося, як створити і використовувати класи в Python, а в наступному розділі обговоримо протокол управління контекстом.

Протокол управління контекстом дозволяє написати клас, що підключається до інструкції with.

Жодного безглуздого питання

Питання: Яким саме типом мови програмування є Python: об’єктно-орієнтованим,  функціональним чи процедурним?

Відповідь: Це чудове запитання — його врешті-решт ставлять чимало програмістів, які переходять на Python. Відповідь полягає в тому, що Python підтримує парадигми програмування, запозичені у всіх цих популярних підходів, і Python заохочує програмістів змішувати та поєднувати їх у разі потреби. Цю концепцію важко осягнути, особливо якщо весь код, що ви писали раніше, був пов’язаний із класами, і ви створювали з них об’єкти (як і в інших мовах програмування на кшталт Java).

Наша порада: нехай це вас не турбує. Створюйте свій код у будь-якій парадигмі, що вам подобається, але не відкидайте інші просто тому, що вони можуть — у наближенні — здатися вам чужими.

Питання: Отже... мабуть неправильно завжди починати зі створення класу?

Відповідь: Це не так, якщо класи — те саме, що потрібно для вашого застосунку. Вам не обов’язково розміщувати весь свій код у класах, але якщо ви забажаєте, Python вам у цьому не завадить.

Досі у цій книжці ми обходилися без створення класів, але зараз опинилися в ситуації, коли є прямий сенс використати їх для розв’язання конкретної проблеми: організації повторного застосування коду обробки бази даних у нашому вебзастосунку. Ми змішуємо та узгоджуємо парадигми програмування, аби вирішити нашу поточну проблему, і це цілком нормально. 

Об’єктно-орієнтований буквар

Перш ніж рухатися далі, зауважимо, що ми не збиралися розглядати класи в усіх подробицях. Наша мета — показати рівно стільки, аби ви змогли впевнено створити клас, що реалізує протокол управління контекстом.

Отже, ми не будемо розглядати теми, яких, можливо, охоче торкнулися би загартовані практики об’єктно-орієнтованого програмування (ООП),— наприклад, питання успадкування і поліморфізму (хоча Python підтримує те й те). І це тому, що з погляду створення диспетчера контексту нас передусім цікавить інкапсуляція.

Якщо термінологія в попередньому абзаці викликала у вас підсвідому паніку, не переймайтеся: ви можете продовжувати читання, навіть не розуміючи чітко, що все це означає.

На попередній сторінці ви дізналися, що для підключення до інструкції with необхідно створити клас. Але перш ніж дізнатися, як це робиться, давайте подивимося, із чого складається клас на мові Python, написавши приклад. Коли ж ви усвідомите, як писати клас, ми повернемося до задачі підключення до інструкції with (у наступному розділі).

Клас пов’язує поведінку і стан

Класи дозволяють зв’язати поведінку і стан разом — в один об’єкт.

Коли ви чуєте слово «поведінка», вважайте, що це — функція, фрагмент коду, який щось робить (тобто реалізує поведінку, якщо вам так більше подобається).

Коли ви чуєте слово «стан», вважайте, що це — змінні, місце для зберігання значень усередині класу. Стверджуючи, що клас пов’язує поведінку і стан разом, ми маємо на увазі, що клас містить функції і змінні.

Підіб’ємо підсумки: якщо ви знаєте, що таке функція і що таке змінні, то ви вже на півдорозі до розуміння того, що таке клас (і як його створити). 

Класи мають методи й атрибути

Поведінка класу в Python визначається створенням методу.

Методами в ООП називають функції, що визначаються всередині класу. Причини, за якими методи назвали методами, а не просто функціями класу, губляться в тумані часу, як і причини, чому атрибути назвали атрибутами, а не змінними класу.


Створення об’єктів із класів

Аби скористатися можливостями класу, потрібно створити об’єкт (як це зробити, показано у прикладі, наведеному нижче). Ця операція називається створенням екземпляра. Почувши слова створення екземпляра, замініть їх подумки словом виклик (тобто вам треба викликати клас, аби створити об’єкт).

Хай як би дивно це звучало, можна створити клас, що не має стану або поведінки, але з погляду Python все одно вважається повноцінним класом. Фактично це порожній клас. Давайте почнемо приклад із порожнього класу та поступово наповнимо його. Ми будемо експериментувати в інтерактивній оболонці >>> і радимо вам повторювати всі дії за нами.

Спочатку створимо порожній клас з ім’ям CountFromBy. Визначення класу починається із ключового слова class, далі слідують ім’я і тіло класу, що реалізує цей клас (після обов’язкової двокрапки):



Інструкція «pass» припустима (тобто синтаксично правильна), але вона нічого не робить. Вважайте її порожнім оператором.

Зверніть увагу: тіло цього класу складається з єдиного ключового слова pass, що в Python являє собою порожню операцію (і нічого не виконує). Ви можете використовувати pass у будь-якому місці, де інтерпретатор очікує зустріти цю інструкцію. Зараз ми не готові визначити всі деталі класу CountFromBy, тому використали pass, аби уникнути будь-яких синтаксичних помилок, що з’явилися би при спробі створити клас без будь-якого коду в його блоці.

Тепер у нас є клас. Давайте створимо з нього два об’єкти, один з ім’ям a, інший — з ім’ям b. Зауважте, що створення об’єкта із класу дуже схоже на виклик функції:


Жодного безглуздого питання

Питання: Як, розглядаючи чужий код, відрізнити інструкцію створення об’єкта CountFromBy ( ) від виклику функції? Як на мене, це виглядає як виклик функції…

Відповідь: Це чудове питання. За зовнішніми ознаками ви нізащо не дізнаєтесь. Однак у спільноті програмістів на Python існує усталена домовленість щодо іменування функцій із використанням малих літер (із підкресленнями для привертання уваги), у той час як CamelCase (об’єднані слова, що починаються з великих літер) використовується для іменування класів. Згідно із цією угодою, має бути зрозуміло, що count_from_by() є викликом функції, тоді як CountFromBy( ) створює об’єкт. Усе добре, поки всі дотримуються цієї угоди, тож і вам наполегливо рекомендуємо це робити. Якщо ви проігноруєте цю рекомендацію, угоду буде розірвано, і більшість програмістів Python, імовірно, уникатимуть вас і вашого коду.

Об’єкти володіють загальною поведінкою, але не станом

Об’єкти, створені з одного класу, володіють загальною поведінкою, реалізованою у класі (спільно використовують методи, визначені у класі), але підтримують власну копію стану (атрибути)


Ця відмінність буде мати більше сенсу, коли ми конкретизуємо приклад CountFromBy.


Теги: python
0 комментариев
Сортировка:
Добавить комментарий