Перестаньте писати класи. Вбудовані в Python функції. Функції range() та xrange()

Серія контенту:

Ми переходимо до однієї з самих цікавих темциклу - об'єктно-орієнтоване програмування (ООП) в Python. З погляду ООП, клас є колекцією даних. Використання класів дає перш за все переваги абстрактного підходу в програмуванні.

  1. Поліморфізм: у різних об'єктах та сама операція може виконувати різні функції. Слово «поліморфізм» має грецьку природу і означає «що має багато форм». Простим прикладом поліморфізму може бути функція count() , що виконує однакову дію для різних типів об'єктів: "abc".count("a") і .count("a"). Оператор плюс поліморфічний при додаванні чисел і при додаванні рядків.
  2. Інкапсуляція: можна приховати непотрібні внутрішні подробиці роботи об'єкта навколишнього світу. Це другий основний принцип абстракції. Він ґрунтується на використанні атрибутів усередині класу. Атрибути можуть мати різні стани у проміжках між викликами методів класу, внаслідок чого сам об'єкт даного класутакож отримує різні стани – state.
  3. успадкування: можна створювати спеціалізовані класи на основі базових. Це дозволяє нам уникати написання повторного коду.
  4. Композиція: об'єкт може бути складовим і включати інші об'єкти.

Об'єктно-орієнтований підхід у програмуванні має на увазі наступний алгоритмдій.

  1. Описується проблема за допомогою звичайної мови з використанням понять, дій, прикметників.
  2. За підсумками понять формулюються класи.
  3. За підсумками дій проектуються методи.
  4. Реалізуються методи та атрибути.

Ми отримали скелет – об'єктну модель. На основі цієї моделі реалізується успадкування. Для перевірки моделі:

  1. пишеться так званий use cases – сценарій можливої ​​поведінки моделі, де перевіряється вся функціональність;
  2. функціонал у своїй може бути виправлений чи доданий.

Об'єктно-орієнтований підхід хороший там, де проект має на увазі довгостроковий розвиток, складається з великої кількостібібліотек та внутрішніх зв'язків.

Механізм класів мови Pythonє сумішшю механізмів класів C++ і Modula-3. Найбільш важливі особливості класів у пітоні:

  1. множинне спадкування;
  2. похідний клас може перевизначити будь-які методи базових класів;
  3. у будь-якому місці можна викликати метод із тим самим ім'ям базового класу;
  4. все атрибути класу в пітоні за умовчанням є public, тобто. доступні звідусіль; всі методи – віртуальні, тобто. перевантажують базові.

Сьогодні ми розглянемо такі аспекти об'єктно-орієнтованого програмування.

  1. Що таке клас?
  2. Атрибути класу.
  3. self.
  4. Спадкування.
  5. ОВП у дії: приклад створення класів.

1. Що таке клас

Клас - це тип користувача. Найпростіша модель визначення класу виглядає так:

ім'я_класу: інструкція 1 . інструкція №

Кожен такий запис генерує свій об'єкт класу. Відмінність від C++ у цьому, що у плюсах опис класу - це лише оголошення, а пітоні - це створення об'єкта. Є також інший тип об'єкта - інстанс класу, що генерується під час виклику:

інстанс_класу = ім'я_класу()

Об'єкт класу та інстанс класу - це два різні об'єкти. Перший генерується на етапі оголошення класу, другий – за виклику імені класу. Об'єкт класу може бути один, інстанс класу може бути скільки завгодно.

Інструкція – це, як правило, визначення функції. При визначенні класу створюється нове місце імен і створюється об'єкт-клас, який є оболонкою для всіх інструкцій.

Об'єкти класів підтримують два види операцій:

  • доступ до атрибутів;
  • створення екземпляра класу.

2. Атрибути класу

Атрибути класу бувають двох видів:

  • атрибути даних;
  • атрибути-методи.

Атрибути даних зазвичай записуються зверху. Пам'ять для атрибутів виділяється в останній момент їх першого присвоювання - або зовні, або всередині методу. Методи розпочинаються зі службового слова def.

Доступ до атрибутів виконується за схемою obj.attrname.

class Simple: u"Простий клас" var = 87 def f(x): return "Hello world"

Тут Simple.var і Simple.f - атрибути користувача. Є також стандартні атрибути:

>>> print Simple.__doc__

Ціле число

>>> print Simple.var.__doc__ int(x[, base]) -> integer ...

Створення екземпляра класу схоже на те, що ми робимо виклик функцій:

smpl = Simple()

Буде створено порожній об'єкт smpl. Якщо ми хочемо, щоб при створенні виконувались якісь дії, потрібно визначити конструктор, який викликатиметься автоматично:

class Simple: def __init__(self): self.list =

Під час створення об'єкта smpl буде створено порожній список List. Конструктору можна передати аргументи:

class Simple: def __init__(self, count, str): self.list = self.count = count self.str = str >>> s = Simple(1,"22") >>> s.count, s.str 1 22

Атрибут даних можна зробити приватним (private) – тобто. недоступним зовні - для цього ліворуч потрібно поставити два символи підкреслення:

class Simple: u"Простий клас з приватним атрибутом" __private_attr = 10 def __init__(self, count, str): self.__private_attr = 20 print self.__private_attr s = Simple(1,"22") print s.__private_at

Останній рядок викликає виняток - атрибут __private_attr придатний лише для внутрішнього використання.

Методи необов'язково визначати всередині тіла класу:

def method_for_simple(self, x, y): return x + y class Simple: f = method_for_simple >>> s = Simple() >>> print s.f(1,2) 3

Порожній клас можна використовувати як заготівлю для структури даних:

class Customer: pass custom = Customer() custom.name = "Вася" custom.salary = 100000

3. self

Зазвичай перший аргумент на ім'я методу - self. Як каже автор мови Гвідо Ван Россум, це не більше, ніж угода: ім'я self не має абсолютно ніякого спеціального значення.

self корисний для того, щоб звертатися до інших атрибутів класу:

class Simple: def __init__(self): self.list = def f1(self): self.list.append(123) def f2(self): self.f1() >>> s = Simple() >>> s .f2() >>> print s.list

Self - це аналог "this" у C++.

4. Спадкування

Визначення похідного класу виглядає так:

class Derived(Base):

Якщо базовий клас визначено не в поточному модулі:

class Derived(module_name.Base):

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

Base.method()

У пітоні існує обмежена підтримка множинного успадкування:

class Derived(Base1,Base2,Base3):

Пошук атрибута здійснюється у такому порядку:

  1. в Derived;
  2. у Base1, потім рекурсивно у базових класах Base1;
  3. у Base2, потім рекурсивно у базових класах Base2
  4. і т.д.

5. Приклад

Створимо два класи: Person – зберігає загальну інформацію про людей – ім'я, професія, зарплата; клас Manager – спеціалізований похідний клас. У класі Person ми створимо свою версію для стандартної вбудованої функції str, яка є за замовчуванням у будь-якому пітонівському класі – для цього вона матиме префікс із двома символами підкреслення ліворуч та праворуч. Коли спробуємо роздрукувати інстанс класу, буде викликана __str__.

# -*- coding: utf-8 -*- class Person: def __init__(self, name, job=None, pay=0): self.name = name self.job = job self.pay = pay def lastName(self ): return self.name.split()[-1] def giveRaise(self, percent): self.pay = int(self.pay * (1 + percent)) def __str__(self): return "" % (self .name, self.pay) class Manager(Person): def __init__(self, name, pay): Person.__init__(self, name, "mgr", pay) def giveRaise(self, percent, bonus=100): Person .giveRaise(self, percent + bonus)

Створюємо першу інстанс класу Person:

>>> ivan = Person("Іван Петров")

Створюємо другий інстанс класу Person:

>>> john = Person ("John Sidorov", job = "dev", pay = 100000)

Викликаємо перевантажену функцію __str__;

>>> print(ivan) >>> print(john)

Виводимо прізвище:

>>> print(ivan.lastName(), john.lastName())

Нараховуємо преміальні:

>>> john.giveRaise(.10)

І отримуємо:

>>> print(john)

Створюємо інстанс класу Manager:

>>> tom = Manager("Tom Jones", 50000)

Нараховуємо мегапреміальні:

>>> tom.giveRaise(.10) print(tom.lastName()) print(tom)("Petrov", "Sidorov") Jones

Висновок

Основні властивості ООП – поліморфізм, успадкування, інкапсуляція. Клас - це тип користувача, що складається з методів і атрибутів. Інстанс класу створюється за допомогою імені класу як функції з параметрами. Об'єкт складається з атрибутів та методів. Атрибут – це змінна, метод – це функція. Відмінність методу від функції в тому, що він має перший параметр - self. Поліморфізм дозволяє нам працювати з різними типамиоб'єктів так, що нам не потрібно думати про те, до якого типу вони належать. Об'єкти можуть приховувати (інкапсулювати) свій внутрішній стан. Це досягається за рахунок того, що доступ до атрибутів здійснюється не безпосередньо, а через методи. Клас може бути похідним від одного або кількох класів. Похідний клас успадковує всі методи базового класу. Базових класів може бути кілька. Об'єктний дизайн має бути прозорим, зрозумілим і описаний, як кажуть, в "термінах людської мови".

Ресурси для скачування

static.content.url=http://www.сайт/developerworks/js/artrating/

Zone = Open source, Linux

ArticleID=512105

ArticleTitle=Програмування на Python: Частина 6. Класи

ОператорОписПриклади
+ Додавання - Підсумовує значення зліва та праворуч від оператора

15 + 5 в результаті буде 20
20 + -3 в результаті буде 17
13.4 + 7 у результаті буде 20.4

- Віднімання - Віднімає правий операнд з лівого 15 - 5 в результаті буде 10
20 - -3 в результаті буде 23
13.4 – 7 в результаті буде 6.4
* Множення - Перемножує операнди 5 * 5 в результаті буде 25
7*3.2 в результаті буде 22.4
-3 * 12 в результаті буде -36
/ Поділ - ділить лівий операнд на правий 15 / 5 в результаті буде 3
5 / 2 в результаті буде 2 (Python 2.x версії при розподілі двох цілих чисел результат буде ціле число)
5.0 / 2 в результаті буде 2.5 (Щоб отримати "правильний" результат хоча б один операнд має бути float)
% Поділ по модулю - ділить лівий операнд на правий і повертає залишок. 6 % 2 в результаті буде 0
7 % 2 в результаті буде 1
13.2 % 5 у результаті 3.2
** Зведення в ступінь - зводить лівий операнд у ступінь правого 5 ** 2 в результаті буде 25
2 ** 3 в результаті буде 8
-3 ** 2 в результаті буде -9
// Цілочисельне поділ - Поділ у якому повертається лише ціла частина результату. Частина після коми відкидається. 12 // 5 в результаті буде 2
4 // 3 в результаті буде 1
25 // 6 в результаті буде 4

Оператори порівняння в Python:

ОператорОписПриклади
== Перевіряє чи обидва операнда. Якщо так, то умова стає істинною. 5 == 5 в результаті буде True
True == False в результаті буде False
"hello" == "hello" в результаті буде True
!= 12 != 5 в результаті буде True
False != False в результаті буде False
"hi" != "Hi" в результаті буде True
<> Перевіряє чи обидва операнда. Якщо ні, то умова стає істинною.

12 <>5 у результаті буде True. Схоже на оператор!

> Перевіряє чи значення лівого операнда, ніж значення правого. Якщо так, то умова стає істинною. 5 > 2 у результаті буде True.
True > False у результаті буде True.
"A" > "B" в результаті буде False.
< Перевіряє, чи менше значення лівого операнда, ніж значення правого. Якщо так, то умова стає істинною. 3 < 5 в результате будет True.
True< False в результате будет False.
"A"< "B" в результате будет True.
>= Перевіряє більше чи дорівнює значення лівого операнда, ніж значення правого. Якщо так, то умова стає істинною. 1 >= 1 у результаті буде True.
23 >= 3.2 у результаті буде True.
"C" >= "D" в результаті буде False.
<= Перевіряє менше чи дорівнює значення лівого операнда, ніж значення правого. Якщо так, то умова стає істинною. 4 <= 5 в результате будет True.
0 <= 0.0 в результате будет True.
-0.001 <= -36 в результате будет False.

Оператори присвоєння в Python:

ОператорОписПриклади
= Надає значення правого операнда лівому. c = 23 присвоє змінної значення 23
+= Додасть значення правого операнда до лівого і надасть цю суму лівого операнда.

з = 5
а = 2
с += а рівносильно: с = с + а. з буде одно 7

-= Забирає значення правого операнда від лівого і надає результат лівого операнда.

з = 5
а = 2
с -= а рівносильно: с = с - а. з буде рівно 3

*= Помножує правий операнд з лівим і надає результат лівому операнду.

з = 5
а = 2
с * = а рівносильно: с = с * а. c дорівнюватиме 10

/= Діляє лівий операнд на правий і надає результат лівому операнду. з = 10
а = 2
с / = а рівносильно: с = с / а. c дорівнюватиме 5
%= Ділить по модулю операнди і надає результат лівому. з = 5
а = 2
з %= а рівносильно: с = з % а. c дорівнюватиме 1
**= Зводить у лівий операнд у ступінь правого та надає результат лівому операнду. з = 3
а = 2
с **= а рівносильно: с = с ** а. c дорівнюватиме 9
//= Здійснює цілий поділ лівого операнда на правий і надає результат лівого операнда. з = 11
а = 2
з //= а рівносильно: з = з // а. c дорівнюватиме 5

Побітові оператори в Python:

Побітові оператори призначені для роботи з даними у бітовому (двійковому) форматі. Припустимо, що ми маємо два числа a = 60; і b = 13. У двійковому форматі вони матимуть такий вигляд:

ОператорОписПриклади
& Бінарний "І" оператор копіює біт в результат тільки якщо біт присутній в обох операндах. (a & b) дасть нам 12, яке у двійковому форматі виглядає так 0000 1100
| Бінарний "АБО" оператор копіює біт, якщо той присутній хоча б в одному операнді. (a | b) дасть нам 61, у двійковому форматі 0011 1101
^ Бінарний "Виняткове АБО" оператор копіює біт тільки якщо біт присутній в одному з операндів, але не в обох відразу. (a ^ b) дасть нам 49, у двійковому форматі 0011 0001
~ Бінарний компліментарний оператор. Є унарним (тобто йому потрібний лише один операнд) змінює біти на зворотні, там де була одиниця ставати нуль і навпаки. (~a) дасть у результаті -61, у двійковому форматі виглядає 1100 0011.
<< Побітове зрушення вліво. Значення лівого операнда "зсувається" вліво на кількість біт вказаних у правому операнді. a<< 2 в результате даст 240, в двоичном формате 1111 0000
>> Побітовий зсув праворуч. Значення лівого операнда "зсувається" праворуч на кількість біт вказаних у правому операнді. a >> 2 дасть 15, у двійковому форматі 0000 1111

Логічні оператори в Python:

ОператорОписПриклади
and Логічний оператор "І". Умова буде істинною якщо обидва операнди істина.

True and True і True.
True and False і False.
False and True і False.
False and False і False.

or Логічний оператор "АБО". Якщо хоча б один із операндів істинний, то і весь вираз буде істинним. True or True і True.
True or False і True.
False or True і True.
False or False і False.
not Логічний оператор "НЕ". Змінює логічне значення операнда протилежне. not True і False.
not False і True.

Оператори членства в Python:

На додаток до перелічених операторів, Pythonприсутні, так звані, оператори членства, призначені для перевірки на наявність елемента в складових типах даних, таких як рядки, списки, кортежі або словники:

Оператори тотожності в Python:

Оператори тотожності порівнюють розміщення двох об'єктів у пам'яті комп'ютера.

Пріоритет операторів у Python

У наступній таблиці описано пріоритет виконання операторів у Pythonвід найвищого (виконується насамперед) до найнижчого.

ОператорОпис
** Зведення в ступінь
~ + - Компліментарний оператор
* / % // Множення, розподіл, розподіл за модулем, цілісний розподіл.
+ - Складання та віднімання.
>> << Побітове зрушення вправо і побітове зрушення вліво.
& Бінарний "І".
^ | Бінарний "Виняткове АБО" та бінарний "АБО"
<= < > >= Оператори порівняння
<> == != Оператори рівності
= %= /= //= -= += *= **= Оператори присвоєння
is is not Тотожні оператори
in not in Оператори членства
not or and Логічні оператори

Ми трохи поговорили, тепер поговоримо про функціях та методах рядків.

Я постарався зібрати тут усі рядкові методи та функції, але якщо я щось забув – поправляйте.

Базові операції

    Конкатенація (додавання)

    >>> S1 = "spam" >>> S2 = "eggs" >>> print (S1 + S2 ) "spameggs"
  • Дублювання рядка

    >>> print ("spam" * 3 ) spamspamspam
  • Довжина рядка (функція len)

    >>> len ("spam") 4
  • Доступ за індексом

    >>> S = "spam" >>> S [0] "s" >>> S [2] "a" >>> S [-2] "a"

    Як видно з прикладу, Python можливий і доступ за негативним індексом, при цьому відлік йде від кінця рядка.

  • Вилучення зрізу

    Оператор вилучення зрізу: . X – початок зрізу, а Y – закінчення;

    символ із номером Y у зріз не входить. За замовчуванням перший індекс дорівнює 0, а другий – довжині рядка.

    >>> s = "spameggs" >>> s [ 3 : 5 ] "me" >>> s [ 2 : - 2 ] "ameg" >>> s [: 6 ] "spameg" >>> s [ 1 :] "pameggs" >>> s [:] "spameggs"

    Крім того, можна задати крок, з яким потрібно витягувати зріз.

    >>> s [:: - 1 ] "sggemaps" >>> s [ 3 : 5 : - 1 ] "" >>> s [ 2 :: 2 ] "aeg"

Інші функції та методи рядків

При викликі методів необхідно пам'ятати, що рядки в Python належать до категорії незмінних послідовностей, тобто всі функції та методи можуть лише створювати новий рядок.

>>> s = "spam" >>> s [1] = "b" Traceback (most recent call last):File "", line 1, in s = "b" TypeError: "str" ​​object does not support item assignment>>> s = s [0] + "b" + s [2:] >>> s "sbam"

Тому всі рядкові методи повертають новий рядок, який потім слід присвоїти змінній.

Таблиця "Функції та методи рядків"

Функція чи методПризначення
S = "str"; S = "str"; S = "str""; S = "str"""
S = "s\np\ta\nbbb" Екрановані послідовності
S = r"C:\temp\new" Неформатовані рядки (пригнічують екранування)
S = b"byte" Рядок
S1 + S2 Конкатенація (складання рядків)
S1*3 Повторення рядка
S[i] Звернення за індексом
S Вилучення зрізу
len(S)Довжина рядка
S.find(str, ,)Пошук підрядки у рядку. Повертає номер першого входження або -1
S.rfind(str, ,)Пошук підрядки у рядку. Повертає номер останнього входження або -1
S.index(str, ,)Пошук підрядки у рядку. Повертає номер першого входження або викликає ValueError
S.rindex(str, ,)Пошук підрядки у рядку. Повертає номер останнього входження або викликає ValueError
S.replace(шаблон, заміна)Заміна шаблону
S.split(Символ)Розбиття рядка по роздільнику
S.isdigit() Чи складається рядок із цифр
S.isalpha() Чи складається рядок з літер
S.isalnum() Чи складається рядок із цифр або букв
S.islower() Чи складається рядок із символів у нижньому регістрі
S.isupper() Чи складається рядок із символів у верхньому регістрі
S.isspace() Чи складається рядок з символів, що не відображаються (пробіл, символ перекладу сторінки ("\f"), "новий рядок" ("\n"), "переклад каретки" ("\r"), "горизонтальна табуляція" ("\t" ) та "вертикальна табуляція" ("\v"))
S.istitle() Чи починаються слова в рядку з великої літери
S.upper() Перетворення рядка до верхнього регістру
S.lower() Перетворення рядка до нижнього регістру
S.startswith(str)Чи починається рядок S із шаблону str
S.endswith(str)Чи закінчується рядок S шаблоном str
S.join(перелік)Складання рядка зі списку з роздільником S
ord(Символ)Символ для його коду ASCII
chr(число)Код ASCII символом
S.capitalize() Перекладає перший символ рядка в верхній регістра всі інші в нижній
S.center(width, )Повертає відцентрований рядок, по краях якого стоїть символ fill (пробіл за замовчуванням)
S.count(str, ,)Повертає кількість неперетинних входжень підрядки в діапазоні [початок, кінець] (0 і довжина рядка за замовчуванням)
S.expandtabs() Повертає копію рядка, де всі символи табуляції замінюються одним або декількома пробілами, залежно від поточного стовпця. Якщо TabSize не вказано, розмір табуляції належить рівним 8 пробілам
S.lstrip() Вилучення пробілових символівна початку рядка
S.rstrip() Видалення символів пробілу в кінці рядка
S.strip() Видалення символів пробілів на початку і в кінці рядка
S.partition(шаблон)Повертає кортеж, що містить частину перед першим шаблоном, сам шаблон і частину після шаблону. Якщо шаблон не знайдено, повертається кортеж, що містить саму рядок, а потім дві порожніх рядки
S.rpartition(Sep)Повертає кортеж, що містить частину перед останнім шаблоном, сам шаблон і частину після шаблону. Якщо шаблон не знайдено, повертається кортеж, що містить два порожні рядки, а потім самий рядок
S.swapcase() Перекладає символи нижнього регіструу верхній, а верхнього – у нижній
S.title() Першу літеру кожного слова переводить у верхній регістр, а решта в нижній
S.zfill(width)Робить довжину рядка не меншого width, за необхідності заповнюючи перші символи нулями
S.ljust(width, fillchar=" ")Робить довжину рядка не меншого width, за необхідності заповнюючи останні символи символом fillchar
S.rjust(width, fillchar=" ")Робить довжину рядка не меншого width, за необхідності заповнюючи перші символи символом fillchar
S.format(*args, **kwargs)

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

Об'єкто-орієнтованість

Це для початківців можна поки що пропустити, і повернутися після прочитання решти матеріалу!

>>> q = >>> p = >>> len(p) 3 >>> p >>> p 2 >>> p.append(’xtra’) >>> p , 4] >>> q

Визначення класу є об'єктом, як і, по суті, все в мові.

Тобто ви можете присвоїти змінній визначення класу:

>>> class MyClass: ... i = 12345 ... def f(x): ... print dir(x) ... return x ... >>> c = MyClass() >>> i 123 >>> c.i 12345 >>> c.f > >>> d=MyClass >>> e=MyClass() >>> e<__main__.MyClass instance at 0x000000000239E808>>>> c<__main__.MyClass instance at 0x000000000239E7C8>>>> d >>> d.i 12345 >>> c.i 12345 >>> c.f > >>> e.f > >>> d.f >>> g = d() >>> g.f >

Відступи

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

Def some_func(z): y = z*2 # Тіло функції return y # Це - теж функція # А це - вже немає y = 1 print(some_func(y))

Змінні в Python

Цілі числа та числа з плаваючою комою

Привласнюючи цисло в змінну без крапки або за допомогою int(), ви отримаєте змінну цілого типу. Результат поділу двох чисел цілого типу також буде цілим числом - залишок від поділу буде відкинуто.

Додайте до точки в кінці, щоб створити змінну типу float:

Рядки в Python

Підстановка значень у рядок

Python дозволяє формувати рядок використовуючи шаблон і підставляючи значення змінних.

Є два варіанти підставити значення в рядок: позиційна підстановка та використання іменованих параметрів.

Позиційна підстановка значень

Output = "Product %s in category %s" % (product, category) output = "You have %s $" % usd_count

У даному випадкуу рядок будуть послідовно підставлені значення змінних.

Використання іменованих параметрів

Output = "Today is %(month)s %(day)s.") % ("month": m, "day": d)

При використанні іменованих параметрів для підстановки у рядок значень буде вибрано значення для підстановки за його ім'ям зі словника.

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

Форматування та виведення рядків

Завершальна кома дозволяє після виведення значення вставляти пробіл замість переходу на новий рядок:

>>> while b< 10: ... print b, ... b += 1 ... 1 2 3 4 5 6 7 8 9 >>> for x in range(1, 11): ... print str(x).rjust(2), str(x*x).rjust(3), ... # Зверніть увагу на кому в кінці попереднього рядка ! ... print str(x*x*x).rjust(4) ...

Відформатований висновок:

1 1 1 2 4 8 3 9 27 4 16 64 5 25 125 6 36 216 7 49 343 8 64 512 9 81 729 10 100 1000

Цей приклад демонструє використання методу рядків rjust(), який вирівнює рядок праворуч у полі заданої ширини, доповнюючи його зліва пробілами. Аналогічно діють методи ljust() та center(). Вони не виводять нічого – просто повертають новий рядок. Якщо вихідний рядок занадто довгий, він не обрізається, а повертається в незмінному вигляді: зазвичай краще внести безлад у розташування колонок, ніж вивести неправильне значення. (Якщо Ви дійсно хочете обрізати її, скористайтеся операцією зрізу: ‘s.ljust(n)’.)

Також може бути корисною є функція zfill(), визначена в модулі string,
яка доповнює зліва нулями рядок з числом, коректно обробляючи знаки плюс та мінус:

>>> import string >>> string.zfill('12', 5) '00012' >>> string.zfill('-3.14', 7) '-003.14' >>> string.zfill('3.14159265359', 5) '3.14159265359'

Використання оператора % виглядає приблизно так:

>>> import math >>> print 'Значення PI приблизно дорівнює %5.3f.' % \ ... math.pi Значення PI приблизно дорівнює 3.142.

% для виведення інформації у 3 стовпці:

>>> for x in range(1,11): ... print '%2d %3d %4d' % (x, x*x, x*x*x) ... 1 1 1 2 4 8 3 9 27 4 16 64 5 25 125 6 36 216 7 49 343 8 64 512 9 81 729 10 100 1000

Операції та операнди

Привласнення

Можна надати значення відразу декільком змінним

A = b = c = 1 a, b = 0, 1

Зведення в ступінь

5 у ступені 2 (5 у квадраті):

Print 5**2

Логічні умови

Оператори in і not in перевіряють, чи є вказане значення в послідовності. Оператори is і is not визначають, чи посилаються дві змінні однією і той самий об'єкт. Всі ці оператори мають однаковий пріоритет, який є нижчим, ніж у арифметичних операторів.

Логічні вирази можуть бути зчеплені: наприклад,< b == c’ проверяет,
чи менше a ніж b і чи рівні b і c.

Логічні вирази можна групувати за допомогою логічних операторів
and і or, і навіть результат можна інвертувати оператором not. Усі логічні
оператори мають менший пріоритет, ніж оператори порівняння. Серед логічних операторів, не має найбільшого пріоритету і or - найменшого.

Вбудовані в Python функції

Всі вбудовані в мову функції можна подивитися тут:

Цикли

Цикл While

Цикл while використовується для багаторазового виконання дій, доки виконується умова:

While expr: suite1

Інструкція while виконується у такому порядку:

1. Обчислюється вираз expr і, якщо він дає брехню, переходить до пункту 3.
2. Виконується блок коду suite1. При цьому виконання у блоці інструкції break
негайно перериває виконання циклу (пункт 3 не виконується), а виконання
інструкції continue перериває виконання блоку коду, після чого виконання
циклу триває з пункту 1. Після закінчення виконання блоку suite1, ви-
виконання циклу триває з пункту 1.
3. Виконується блок коду suite2 (гілка else). Інструкції break та continue у
цьому блоці вважаються такими, що належать до зовнішнього циклу.

Цикл For

Цикл for у мові Python перебирає елементи довільної послідовності (наприклад, списку або рядка) в порядку їхнього слідування:

A = ['кіт', 'вікно', 'викинути'] >>> for x in a: ... print x, len(x) ... кіт 3 вікно 4 викинути 9

Особливості роботи циклу for Python

Інструкція for використовується для перебору елементів послідовності:

For lvalue in sequence: suite1

Вираз sequence обчислюється один раз і має давати послідовність (об'єкт, для якого визначено операцію отримання елемента за індексом; якщо індекс виходить за межі діапазону, має генеруватися виняток IndexError).

Для кожного елемента послідовності sequence в порядку зростання індексів, починаючи з 0, виконується присвоювання lvalue елемента послідовності та виконується блок коду suite1.

Після того, як послідовність вичерпана (визначається за згенерованим винятком IndexError), якщо присутня гілка else, виконується блок suite2.

Виконання інструкції break у блоці suite1 негайно перериває виконання циклу (гілка else ігнорується). При виконанні інструкції continue в блоці suite1 пропускається залишок блоку і виконання циклу продовжується після присвоювання lvalue наступного елемента послідовності sequence або виконується гілка else, якщо в послідовності немає наступного елемента.

Ви можете надавати змінної або змінним, що входять до lvalue, - це ніяк не позначиться на наступному елементі, який буде присвоєний lvalue. Змінні, що входять до lvalue, не видаляються після закінчення циклу і зберігають останні надані їм значення. Однак, якщо послідовність sequence порожня, lvalue не буде присвоєно жодного значення (тобто, використовуючи ці змінні без додаткової перевірки, Ви маєте шанс отримати помилку NameError).

Зміна послідовності, що перебирається.

Змінюючи послідовність, елементи якої ви перебираєте, будьте уважні. Поточний елемент послідовності визначається значенням внутрішнього лічильника. Кінець послідовності визначається, за винятком IndexError при спробі отримати черговий елемент. Таким чином, якщо в блоці suite1 Ви видалите поточний або один із пройдених елементів послідовності, наступний елемент буде пропущено.

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

For x in a[:]: if x< 0: a.remove(x)

Функції range() та xrange()

Якщо Вам необхідно перебирати послідовність чисел, то знадобиться вбудована
функція range(). Вона створює список, що містить арифметичну прогресію:
>>> range(10)

Функція xrange працює аналогічно, тільки замість створення списку створює об'єкт типу xrange — його значення можна перебрати в циклі, але не можна змінювати

>>> type(range(2)) >>> type(xrange(2))

Інструкції break та continue, гілка else у циклах

Інструкція break виходить з внутрішнього вкладеного циклу for або while. Інструкція continue продовжує виконання циклу з наступної ітерації.

Цикли можуть мати гілку else, яка виконується при “нормальному” виході (вичерпування послідовності в циклі for, незадоволення умови у циклі while), без переривання інструкцією break. Продемонструємо її використання на прикладі пошуку простих чисел:

>>> for n in xrange(2, 10): ... for x in xrange(2, n): ... if n % x == 0: ... print n, '=', x, ' *', n/x ... break ... else: ... print n, '- просте число' ... 2 - просте число 3 - просте число 4 = 2 * 2 5 - просте число 6 = 2 * 3 7 - просте число 8 = 2 * 4 9 = 3 * 3

Функції

>>> def fib(n):

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

>>> def fib(n): ... ’’’Виводить числа Фібоначчі в межах заданого числа''' ... a, b = 0, 1 ... while b< n: ... print b, ... a, b = b, a+b

>>> q = range(5) >>> def ch(l): ... l.append("New one!") ... >>> q >>> ch(q) >>> q

Інструкція return виходить із функції та повертає значення. Без аргументів return використовується виходу з середини процедури, у разі повертається значення None.

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

I = 5 def (arg = i): print arg i = 6 f () виведе 5.

Важливо: значення за замовчуванням обчислюється лише один раз. Це відображається в тому випадку, коли аргумент зі значенням за промовчанням є об'єктом, який допускає зміни, такі як список або словник. Наприклад, наступна функція накопичує передані аргументи.

Def f(a, l = ): l.append(a) return l print f(1) print f(2) print f(3)

Результат виконання буде наступний:

Довільний набір аргументів

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

Def fprintf(file, format, *args): file.write(format % args)

Іменовані аргументи

Функція може бути викликана за допомогою іменованих аргументів (keyword
arguments) як 'keyword = value'.

Def example(formal, *arguments, **keywords): print "Звичайні аргументи:", formal print '-'*40 for arg in arguments: print arg print '-'*40 for kw in keywords.keys(): print kw, ':', keywords

Python lambda функції

lambda -функція робить те саме, що й звичайна функція.

На відміну від звичайної, lambda використовує скорочений синтаксис: список аргументів записується без дужок, а ключове слово return відсутнє. Тіло функції може містити лише один вираз. lambda-функція немає імені, але може бути викликана через змінну, якій вона присвоєна.

>>> g = lambda x: x*2 >>> g(3)

Введення та виведення даних у Python

Читання та запис файлів

Вбудована функція open() повертає об'єкт-файл (file) і зазвичай використовується з двома аргументами: 'open(filename, mode)'.

>>> f=open('/tmp/workfile', 'wb') >>> print f

Перший аргумент - рядок, що містить ім'я файлу, другий аргумент - рядок, що містить кілька символів, що описують режим використання файлу. Режим може бути 'r', якщо файл відкривається тільки для читання, 'w' - тільки для запису (існуючий файл буде перезаписаний), і 'a' - для дописування до кінця файлу. У режимі 'r+' файл відкривається одразу для читання та запису. Аргумент mode не обов'язковий: якщо він опущений, мається на увазі 'r'.

У Windows (а в деяких випадках і Macintosh) файли за замовчуванням відкриваються в текстовому режимі - для того, щоб відкрити файл у двійковому режимі, необхідно до рядка режиму додати 'b'. Слід пам'ятати, що двійкові дані, такі як картинки у форматі JPEG і навіть текст у UNICODE, під час читання з файлу або запису у файл, відкритий у текстовому режимі, будуть зіпсовані! Найкращий спосіб захистити себе від неприємностей - завжди відкривати файли в двійковому режимі, навіть на тих плат-формах, де двійковий режим використовується за умовчанням (можливо у Вас коли-небудь виникне бажання запустити програму на іншій платформі).

Модуль pickle

Якщо у вас є об'єкт x і файловий об'єкт f , відкритий для запису, найпростіший спосібзберегти об'єкт вимагатиме лише один рядок коду:

Pickle.dump(x, f)

Так само просто можна відновити об'єкт (f - файловий об'єкт, відкритий для читання):

X = pickle.load(f)

Вбудовані функції Python

У мову Python входить безліч функцій, таких як map() і zip(), що помітно спрощують обчислення.

Структури даних Python

Списки

Список значень, розділених комами, укладений у квадратні
дужки. Зовсім не обов'язково, щоб елементи списку були одного типу

A = ['spam', 'eggs', 100, 1234]

Нумерація елементів списку подібна до рядків — перший елемент йде під номером 0.

Методи роботи зі списками

append, pop та insert

Append додає до кінця списку новий елемент.

Вставити елемент у початок або іншу позицію списку дозволяє метод insert - Ви вказуєте індекс елемента, перед яким новий елемент буде додано:

>>> a.insert(2, -1)

pop() повертає останній елемент списку, видаляючи його зі списку.

index та count

Index дозволить знайти, в якому положенні знаходиться перший елемент із певним значенням.

remove, sort, reverse

Використання списків

append і pop дозволяють використовувати списки як стек:

>>> stack = >>> stack.append(6) >>> stack.append(7) >>> stack >>> stack.pop() 7 >>> stack

Також легко використовувати список як черга елементів — додаючи за допомогою append і витягуючи перший черги за допомогою pop(0):

>>> queue = ["Eric", "John", "Michael"] >>> queue.append("Terry") # Terry додали до черги >>> queue.append("Graham") # Graham додали до черги >>> queue.pop(0) 'Eric' >>> queue.pop(0) 'John' >>> queue ['Michael', 'Terry', 'Graham']

Зрізи

Зрізи не можна робити зі словників та множин або наборів.
Найпоширеніше застосування зрізів у python – створення копії послідовності чи її частини.
Розглянемо зріз як частину послідовності. Наприклад, кілька зрізів зі списку:

>>> s = #простий список >>> s[:] #копія списку, часто дуже корисно >>> s # всі елементи крім першого >>> s[-3:] # останні 3 елементи >>>s #відкидаємо перші та останні 2

Зрізи можуть бути з трьома параметрами:

S[::2] #парні елементи >>> s #елементи з першого по четвертий з кроком 2

Всі ці дії можна провертати з рядками, кортежами та списками.

>>> "Hello Dolly!" "el ol!"

Як «розгорнути» рядок (кортеж, список):

>>> "God saw I was dog"[::-1] "god saw I was doG" >>> #негативний крок може виявитися граблями, якщо не знати особливостей.

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

>>> s = list(range(10)) #заповнюємо 0..9 >>> del s #видаляємо елементи між третім і передостаннім з кроком 2 >>> s [ 0, 1, 2, 4, 6, 8, 9]

Ще можна вставляти елементи:
У варіанті заміни:

>>> s=list("AF") #список був , ми замінили вказані елементи на ['A','F'] >>> #так, ще в такій конструкції повинні збігатися розміри, це легше зрозуміти спробувавши >>> s [0, 1, "A", 4, "F", 8, 9]

Ну, або варіант вставки простіше:

>>> s = ["4 was here"] # заміна послідовного шматочка >>> s [ 0, 1, "A", "4 was here", "F", 8, 9] >>> s = [" after zero"] #або просто вставка >>> s [ 0, "after zero", 1, "A", "4 was here", "F", 8, 9]

Можна створити клас, з якого можна буде робити зрізи.
Перевизначити __getitem__, __setitem__ та __delitem__.
З першого погляду все здається гранично простим, але якщо придивитися, то __getitem__(self, key) – отримує лише один параметр, key, а у зрізу у нас може бути цілих 3 числа… Все гранично просто: якщо хтось намагається зрізати шматочок від нашого об'єкта, значенням key функція отримає об'єкт типу slice:

>>> class MySliceble(): def __getitem__(self, key): if isinstance(key, slice): return list(range(key.start, key.stop, key.step)) else: raise Exception("Trying to access by index") >>> my = MySliceble() >>> my

Звичайно, приклад дуже символічний, але зрозуміти можна: об'єкт класу slice має три властивості: start, stop і step, відповідають числам з дужок зрізу. Потрібно бути уважним, якщо число пропущено, то значення буде None, наприклад [::] буде slice(None, None, None), а [:-3] буде slice(None, -3, None).
Заміну/вставку та видалення зрізів робимо за аналогією.

Кортежі - tuple

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

>>> t = 1, ['foo', 'bar'] >>> t (1, ['foo', 'bar']) >>> t = Traceback (innermost last): File " ", line 1, in ? TypeError: object doesn't support item assignment >>> t.append('baz') >>> t(1, ['foo', 'bar', 'baz'])

Створення порожнього кортежу

c = ()

Створення кортежу з одного елемента

c = (1,)

Словники — Dictionaries

Найкраще представляти словник як невпорядковане безліч пар ключ: значення, з вимогою унікальності ключів у межах одного словника. Пара фігурних дужок () створює порожній словник. Поміщаючи список пар key: value, розділених за-п'ятими, у фігурні дужки, Ви задаєте початковий вміст словника. У такому вигляді записується словник при виведенні.

Щоб звернутися до елемента словника, потрібно вказати ключ у квадратних дужках.

>>> tel = ("jack": 4098, "sape": 4139) >>> tel["guido"] = 4127 >>> tel ("sape": 4139, "guido": 4127, "jack": 4098) >>> tel["jack"] 4098 >>> del tel["sape"] >>> tel["irv"] = 4127 >>> tel ("guido": 4127, "irv": 4127, "jack": 4098) >>> tel.keys() ["guido", "irv", "jack"] >>> "guido" in tel True

Модулі в Python

Модуль – файл, що містить визначення та інші інструкції мови Python. Ім'я
файл утворюється шляхом додавання до імені модуля суфікса (розширення) '.py'. У
В межах модуля, його ім'я доступне в глобальній змінній __name__.

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

Імпортування функцій та змінних

Такий варіант інструкції import дозволяє імпортувати всі імена, визначені в модулі, крім імен, що починаються з символу підкреслення (_):
>>> from fibo import *

Починаючи з версії Python 2.0, можна зробити заміну імен, що імпортуються, при виконанні інструкції import:

Import string as _string from anydbm import open as dbopen

Функція dir()

Для визначення імен, визначених у модулі, можна використовувати вбудовану функцію dir(). Вона повертає відсортований список рядків:

>>> import fibo, sys >>> dir(fibo) ['__name__', 'fib', 'fib2'] >>> dir(sys) ['__name__', 'argv', 'builtin_module_names', 'copyright' , 'exit', 'maxint', 'modules', 'path', 'ps1', 'ps2', 'setprofile', 'settrace', 'stderr', 'stdin', 'stdout', 'version']

Без аргументів dir() повертає список імен, визначених у поточній області видимості:

Список, що повертається функцією dir() не містить імена вбудованих функцій та змінних - вони визначені у стандартному модулі __builtin__:

Файл '__init__.py' необхідний для того, щоб Python розпізнавав каталог, як пакет, що містить - таким чином запобігається маскування повноцінних модулів, розташованих далі в шляхах пошуку, каталогами з поширеними іменами (такими як 'string'). У найпростішому випадку '__init__.py' - порожній файл, але може містити код ініціалізації пакета та/або встановлювати змінну __all__,

Інструкція import використовує таку угоду: якщо в ініцілізаційному файлі '__init__.py' визначено список з ім'ям __all__, він використовується як список імен модулів, які повинні імпортуватися при використанні 'from package import *'. Підтримка цього списку відповідно до поточного складу пакета покладається на автора. Можна також не визначати список __all__, якщо автори не вважають доречним імпортування *.

Обробка винятків

Наступний приклад демонструє користувачеві запрошення до тих пір, поки не буде введено ціле число або виконання не буде перервано (зазвичай Ctrl-C). У другому випадку генерується виняток KeyboardInterrupt.

While 1: try: x = int(raw_input("Введіть ціле число: ")) break except ValueError: print "Ви помилилися, спробуйте ще раз..."

Інструкція try може мати більше однієї галузі except, визначаючи обробники для різних винятків. Виконуватиметься (як максимум) лише один із них. Обробляються тільки винятки, генеровані у відповідній гілки try, але не в інших обробниках інструкції try. Після ключового слова except може бути зазначено кілька типів винятків як кортежу:

Except (RuntimeError, TypeError, NameError): ... pass

Після всіх гілок except, інструкція try може містити гілка else, яка буде виконуватися у випадку, якщо під час виконання try гілки виключення не генеруються.

Класи в Python

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

Синтаксис визначення класу

Найпростіша модель визначення класу виглядає так:

Class class_name: some_instruction

Створення об'єктів - екземплярів класу

Створення екземпляра класу використовує запис функцій. Просто вважайте об'єкт клас функцією без параметрів, що повертає створений екземпляр класу.

X = MyClass()

У наведеному прикладі створюється порожній об'єкт.

Приклад створення класу з атрибутами та методами:

Class MyClass: i = 12345 def f(x): return "Привіт всьому світу!"

У багатьох випадках необхідно створювати об'єкт із певним початковим станом - для цього клас повинен містити спеціальний метод __init__(),

class MyClass: def __init__(self): self.data =

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

Для більшої гнучкості метод __init__() звичайно може мати аргументи. У цьому випадку аргументи, які використовуються при створенні екземпляра класу, передаються методу __init__(). Наприклад:

>>> class Complex: ... def __init__(self, realpart, imagpart): ... self.r = realpart ... self.i = imagpart ... >>> x = Complex(3.0, -4.5) >>> x.r, x.i (3.0, -4.5)

Методи екземплярів класу

Зазвичай метод викликають безпосередньо:

У нашому прикладі він поверне рядок “Привіт усьому світу!”. При цьому зовсім не обов'язково викликати метод прямо. x.f є об'єктом, і його можна зберегти для подальшого використання:

Xf = x.f while 1: print xf()

Особливість методів класу полягає в тому, що вони отримують об'єкт, до якого належать, як перший аргумент. У нашому прикладі виклик x.f() повністю еквівалентний MyClass.f(x). Загалом виклик методу, прив'язаного до об'єкта, зі списком з n аргументів повністю еквівалентний виклику відповідного не прив'язаного методу-функції зі списком аргументів, отриманим додаванням об'єкта перед першим аргументом.

успадкування

Визначення похідного класу з ім'ям ClassB має такий вигляд:

Class ClassB(ClassA): ...

Базовий клас (ClassA) повинен бути визначений в області видимості, де знаходиться визначення похідного класу ClassB. Замість базового класу можна використовувати вираз.

Наприклад, якщо базовий клас визначено в іншому модулі:

Class ClassB(ModulA.ClassA):

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

>>> class ClassA: ... a = "A" ... b = "B" ... def Print_A(self): ... print a ... def Print_B(self): ... print self .b ... def Print_Both(self): ... pring ... def PrintBoth(self): ... print "Printing A" ... self.Print_A() ... print "Printing B" .. self.Print_B() ... >>> a = "aaa" >>> cc = ClassA() >>> cc.Print_A() aaa >>> cc.Print_B() B >>> cc.PrintBoth( ) Printing A aaa Printing B B >>> classB(ClassA): ... def Print_A(self): ... print self.a ... >>> ccc = ClassB() >>> ccc.PrintBoth() Printing A A Printing B B

Перевизначаючи метод у похідному класі, Ви також можете захотіти викликати метод базового класу з тим самим ім'ям. Це можна зробити: просто викличте метод, явно вказавши ім'я класу:

>>> class ClassC(ClassA): ... def Print_A(self): ... print "Print using old method from ClassA" ... ClassA.Print_A(self) ... >>> c = ClassC() >>> c.PrintBoth() Printing A Print використовуючи новий метод від ClassA aaa Printing B B

Множинне успадкування в Python

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

>>> class ClassD(ClassB, ClassA): ... "Checking inheritance" ... ... >>> d = ClassD() >>> d.PrintBoth() Printing A A Printing B B

Важливий нюанс при множинному успадкування— це схема пошуку об'єктів (дозвіл імен) — спочатку пошук ведеться в глибину, потім зліва направо.

Це означає, що якщо ім'я методу або атрибуту є в обох класах, від яких ви успадкуєте, то буде використано те, що є у першому або його предках.

Приватні атрибути

>>> class clA: ... __privateA = "aaa" ... def prn(s): ... print s.__privateA ... >>> class clB(clA): ... __privateA = "bbb" ... >>> A = clB() >>> A.prn() aaa >>> A.__privateA Traceback (останній останній час): File "", line 1, в AttributeError: clB instance has no attribute " __privateA" >>> dir(A) ["__doc__", "__module__", "_clA__privateA", "_clB__privateA", "prn"] >>> A._clB__privateA "bbb" >>>

Практичні приклади

Як прибрати з рядка всі символи, окрім цифр, у Python?

>>> import re >>> re.sub("[^0-9]", "", "sdkjh987978asd098as0980a98sd") "987978098098098"

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

Class Test (object): @classmethod def initialize_class(cls): def print(cls.print_proc), I see an unbound method; so if I # get a Test object o, I can call o.print_proc("Hello")

2018-12-04T00:00Z

досить складно зрозуміти

Ну це досить складна тема, і вона пов'язана з дескрипторами.

Почнемо з функції. Тут все ясно - ви просто називаєте це, всі надані аргументи передаються за його виконання:

>>> f = A.__dict__["f1"] >>> f(1) 1

Регулярний TypeError виникає у разі виникнення проблем із кількістю параметрів:

>>> ", line 1, in TypeError: f1() так само 1 argument (0 given)

Тепер методи. Методи – це функції з невеликою кількістю спецій. Тут є дескриптори. Як описано в моделі даних, A.f1 і A().f1 перекладаються в A.__dict__["f1"].__get__(None, A) і type(a).__dict__["f1"].__get__(a, type (a)) відповідно. І результати цих __get__ відрізняються від функції raw f1. Ці об'єкти є обгортками навколо вихідного f1 і містять додаткову логіку.

У разі unbound method ця логіка включає перевірку того, чи є перший аргумент екземпляром A:

>>> f = A.f1 >>> f() Traceback (most recent call last): File " ", line 1, in TypeError: unbound метод f1() повинен бути зв'язаний з початком як перший argument (got nothing instead) >>> f(1) Traceback (most recent call last): File " ", line 1, in TypeError: unbound метод f1() повинен бути названий з останньою як перший argument (got int instance instead)

Якщо ця перевірка завершується успішно, вона виконує оригінальний f1 з цим екземпляром як перший аргумент:

>>> f(A())<__main__.A object at 0x800f238d0>

Зверніть увагу, що атрибут im_self дорівнює None:

>>> f.im_self is None True

У разі bound method ця логіка негайно постачає вихідний f1 з екземпляром A, який був створений (цей екземпляр фактично зберігається в im_self):

>>> f = A().f1 >>> f.im_self<__main__.A object at 0x800f23950>>>> f()<__main__.A object at 0x800f23950>

Таким чином, bound означає, що базова функціяприв'язана до деякого екземпляра. unbound означає, що вона все ще пов'язана, але тільки з класом.

2018-12-11T00:00Z

Моя інтерпретація є такою.

Фрагменти Function класу:

Class Function(object): . . . def __get__(self, obj, objtype=None): "Simulate func_descr_get() in Objects/funcobject.c" if obj is None: return self return types.MethodType(self, obj)

Class Function(object): . . . def __get__(self, obj, objtype=None): "Simulate func_descr_get() in Objects/funcobject.c" return types.MethodType(self, obj, objtype)

  1. Якщо функція викликається без класу чи екземпляра, це проста функція.
  2. Якщо функція викликається з класу або екземпляра, її __get__ викликається для вилучення загорнутої функції:
    а. Bx збігається з B.__dict__["x"].__get__(None, B) . У Python 3 це повертає звичайну функцію. У Python 2 це повертає незв'язану функцію.

    б. bx аналогічний type(b).__dict__["x"].__get__(b, type(b) . Це поверне пов'язаний метод як у Python 2, так і в Python 3, що означає, що self буде неявно переданий як перший аргумент .