HTML Diff
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>