0 added
0 removed
Original
2026-01-01
Modified
2026-02-26
1
<h2>Метод __init__</h2>
1
<h2>Метод __init__</h2>
2
<p>Теперь, когда мы знакомы со связанными методами, настало время рассказать про самый важный метод в Python: метод __init__ ("dunder-init", "дандер инит"). Этот метод отвечает за<em>инициализацию</em>экземпляров класса после их создания.</p>
2
<p>Теперь, когда мы знакомы со связанными методами, настало время рассказать про самый важный метод в Python: метод __init__ ("dunder-init", "дандер инит"). Этот метод отвечает за<em>инициализацию</em>экземпляров класса после их создания.</p>
3
<p>На прошлых уроках Бобу - экземпляру класса Person, мы задавали имя уже после того, как сам объект был создан. Такое заполнение атрибутов объекта и выглядит громоздко и может приводить к разного рода ошибкам: объект может какое-то время находиться в "недозаполненном" (более общее название - "неконсистентном") состоянии.<em>Инициализатор</em>же позволяет получить уже полностью настроенный экземпляр.</p>
3
<p>На прошлых уроках Бобу - экземпляру класса Person, мы задавали имя уже после того, как сам объект был создан. Такое заполнение атрибутов объекта и выглядит громоздко и может приводить к разного рода ошибкам: объект может какое-то время находиться в "недозаполненном" (более общее название - "неконсистентном") состоянии.<em>Инициализатор</em>же позволяет получить уже полностью настроенный экземпляр.</p>
4
<p>Реализуем класс Person так, чтобы имя можно было указывать при создании объекта:</p>
4
<p>Реализуем класс Person так, чтобы имя можно было указывать при создании объекта:</p>
5
<p>Теперь нет нужды иметь в классе атрибут name = 'Noname', ведь все объекты получают имена при инстанцировании.</p>
5
<p>Теперь нет нужды иметь в классе атрибут name = 'Noname', ведь все объекты получают имена при инстанцировании.</p>
6
<h2>Методы и протоколы</h2>
6
<h2>Методы и протоколы</h2>
7
<p>Вы заметили, что Python сам вызывает метод __init__ в нужный момент? Это же касается большинства dunder-методов: таковые вы только объявляете, но вручную не вызываете. Такое поведение часто называют<em>протоколом</em>(или<em>поведением</em>): класс реализует некий протокол, предоставляя нужные dunder-методы. А Python, в свою очередь, работает с объектом посредством протокола.</p>
7
<p>Вы заметили, что Python сам вызывает метод __init__ в нужный момент? Это же касается большинства dunder-методов: таковые вы только объявляете, но вручную не вызываете. Такое поведение часто называют<em>протоколом</em>(или<em>поведением</em>): класс реализует некий протокол, предоставляя нужные dunder-методы. А Python, в свою очередь, работает с объектом посредством протокола.</p>
8
<p>Продемонстрирую протокол получения длины имени объекта:</p>
8
<p>Продемонстрирую протокол получения длины имени объекта:</p>
9
<p>Я объявил метод dunder-len, и объекты класса Person научились возвращать "свою длину" (да, пример надуманный, но суть отражает). Вызов функции len на самом деле приводит к вызову метода __len__ у переданного в аргументе объекта.</p>
9
<p>Я объявил метод dunder-len, и объекты класса Person научились возвращать "свою длину" (да, пример надуманный, но суть отражает). Вызов функции len на самом деле приводит к вызову метода __len__ у переданного в аргументе объекта.</p>
10
<h2>Возврат объектов</h2>
10
<h2>Возврат объектов</h2>
11
<p>Внутри объектов можно также создавать новые объекты и возвращать их. Строго говоря, в Python все есть объект от чисел и строк до функций, но в этом примере мы создадим объект явно.</p>
11
<p>Внутри объектов можно также создавать новые объекты и возвращать их. Строго говоря, в Python все есть объект от чисел и строк до функций, но в этом примере мы создадим объект явно.</p>
12
<h2>Протоколы и "утиная типизация"</h2>
12
<h2>Протоколы и "утиная типизация"</h2>
13
<p>Существует такой термин: "утиная типизация" ("duck typing") - "Если что-то крякает как утка и плавает как утка, то возможно это утка и есть.". Данный термин, пусть и звучит как шутка, описывает важный принцип построения абстракций: коду практически всегда достаточно знать о значении, с которым этот код работает, что это значение обладает нужными свойствами. Все остальное - не существенно.</p>
13
<p>Существует такой термин: "утиная типизация" ("duck typing") - "Если что-то крякает как утка и плавает как утка, то возможно это утка и есть.". Данный термин, пусть и звучит как шутка, описывает важный принцип построения абстракций: коду практически всегда достаточно знать о значении, с которым этот код работает, что это значение обладает нужными свойствами. Все остальное - не существенно.</p>
14
<p>Если коду достаточно знать, что сущность умеет плавать и крякать, то код не должен проверять сущность на фактическую принадлежность к уткам. Это позволит коду работать с робо-утками, даже если все настоящие утки вымрут, ведь код работает с<em>абстрактными утками</em>.</p>
14
<p>Если коду достаточно знать, что сущность умеет плавать и крякать, то код не должен проверять сущность на фактическую принадлежность к уткам. Это позволит коду работать с робо-утками, даже если все настоящие утки вымрут, ведь код работает с<em>абстрактными утками</em>.</p>
15
<p>Протоколы в Python являются представлением идеи утиной типизации в коде. Так циклу for незачем знать, что за источник он обходит, лишь бы источник поддерживал<em>протокол итерации</em>. Так и вы, когда возникает желание узнать о значении, уж не список ли это, всегда проверяйте себя: возможно вашему коду<em>не нужно</em>знать, что значение является списком.</p>
15
<p>Протоколы в Python являются представлением идеи утиной типизации в коде. Так циклу for незачем знать, что за источник он обходит, лишь бы источник поддерживал<em>протокол итерации</em>. Так и вы, когда возникает желание узнать о значении, уж не список ли это, всегда проверяйте себя: возможно вашему коду<em>не нужно</em>знать, что значение является списком.</p>
16
<p>К примеру, в Python длина объекта определяется не его типом, а наличием метода __len__(). Это и есть утиная типизация: если у объекта есть __len__(), значит len(obj) сработает:</p>
16
<p>К примеру, в Python длина объекта определяется не его типом, а наличием метода __len__(). Это и есть утиная типизация: если у объекта есть __len__(), значит len(obj) сработает:</p>
17
<p>Song - это не список, не строка, и вообще не "последовательность". Но у него реализован метод __len__(). Поэтому len(track) работает. То, что делает len() - это по сути вызывает метод __len__() у переданного объекта.</p>
17
<p>Song - это не список, не строка, и вообще не "последовательность". Но у него реализован метод __len__(). Поэтому len(track) работает. То, что делает len() - это по сути вызывает метод __len__() у переданного объекта.</p>
18
<p>Протоколов в Python существует великое множество. Вы можете заставить объекты вашего класса<em>вести себя</em>подобно словарям и спискам (bob['key'] и bob[-1]), походить на функции (bob(42, foo=True)), уметь "складываться и умножаться" (bob + alice). И Python будет обращаться с объектами соответствующим образом, ведь он тоже всегда следует протоколам - несмотря на то, что уж интерпретатору-то всегда известно, что за объект вы ему подсунули.</p>
18
<p>Протоколов в Python существует великое множество. Вы можете заставить объекты вашего класса<em>вести себя</em>подобно словарям и спискам (bob['key'] и bob[-1]), походить на функции (bob(42, foo=True)), уметь "складываться и умножаться" (bob + alice). И Python будет обращаться с объектами соответствующим образом, ведь он тоже всегда следует протоколам - несмотря на то, что уж интерпретатору-то всегда известно, что за объект вы ему подсунули.</p>