Python: задачки и вопросы
7.6K subscribers
1.23K photos
2 videos
1 file
102 links
Вопросы и задачки для подготовки к собеседованиям и прокачки навыков

Разместить рекламу: @tproger_sales_bot

Правила общения: https://tprg.ru/rules

Другие каналы: @tproger_channels

Другие наши проекты: https://tprg.ru/media
Download Telegram
🧩 Что выведет код?
Anonymous Quiz
23%
1
52%
2
13%
(1, 2)
12%
Error
👍1👎1
В этой задаче мы имеем дело с концепцией Метаклассов. При выполнении 𝚌𝚕𝚊𝚜𝚜 𝙴𝚐𝚐𝚜(𝚖𝚎𝚝𝚊𝚌𝚕𝚊𝚜𝚜=𝙼𝚎𝚝𝚊𝙵𝚞𝚗𝚌): происходит следующее:

🔘 Вызывается функция 𝙼𝚎𝚝𝚊𝙵𝚞𝚗𝚌 с тремя обязательными аргументами:
− 𝚌𝚕𝚊𝚜𝚜𝚗𝚊𝚖𝚎: строка «𝙴𝚐𝚐𝚜»
− 𝚜𝚞𝚙𝚎𝚛𝚜: кортеж родительских классов (<𝚌𝚕𝚊𝚜𝚜 '𝚘𝚋𝚓𝚎𝚌𝚝'>,)
− 𝚌𝚕𝚊𝚜𝚜𝚍𝚒𝚌𝚝: словарь атрибутов класса, содержащий '__𝚖𝚘𝚍𝚞𝚕𝚎__', '__𝚚𝚞𝚊𝚕𝚗𝚊𝚖𝚎__', '𝚍𝚊𝚝𝚊': 𝟸 и '𝚖𝚎𝚝𝚑'
🔘 Функция модифицирует словарь атрибутов: 𝚌𝚕𝚊𝚜𝚜𝚍𝚒𝚌𝚝['𝚍𝚊𝚝𝚊'] = 𝟷
🔘 Функция возвращает объект класса, созданный с помощью 𝚝𝚢𝚙𝚎(𝚌𝚕𝚊𝚜𝚜𝚗𝚊𝚖𝚎, 𝚜𝚞𝚙𝚎𝚛𝚜, 𝚌𝚕𝚊𝚜𝚜𝚍𝚒𝚌𝚝)
🔘 Создается экземпляр 𝚇 класса 𝙴𝚐𝚐𝚜
🔘 Выводится значение атрибута 𝚍𝚊𝚝𝚊 экземпляра (которое теперь равно 𝟷, а не 𝟸)

Функция 𝙼𝚎𝚝𝚊𝙵𝚞𝚗𝚌 является «простейшей (и вполне законной) версией метакласса, которая позволяет перехватить процесс создания класса и модифицировать его атрибуты перед созданием. В данном случае метакласс изменяет значение атрибута 𝚍𝚊𝚝𝚊 с 𝟸 на 𝟷, демонстрируя возможность динамической модификации класса во время его создания.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1👎1
🪤 Что выведет код?
Anonymous Quiz
32%
1
41%
2
23%
(1, 2)
4%
Error
👍2👎1
В данном коде определены:
🔘 Метакласс 𝙼 с атрибутом 𝚊𝚝𝚝𝚛 = 𝟷
🔘 Суперкласс 𝙰 с атрибутом 𝚊𝚝𝚝𝚛 = 𝟸
🔘 Класс 𝙱, который наследует от 𝙰 и использует метакласс 𝙼

Ключевой момент заключается в том, как работает наследование атрибутов в 𝙿𝚢𝚝𝚑𝚘𝚗.

Марк Лутц «Изучаем Python», глава 40:

«Экземпляры будут видеть имена в классе, но не в его метаклассе».

«__𝚍𝚒𝚌𝚝__ каждого класса в порядке 𝙼𝚁𝙾 (𝙼𝚎𝚝𝚑𝚘𝚍 𝚁𝚎𝚜𝚘𝚕𝚞𝚝𝚒𝚘𝚗 𝙾𝚛𝚍𝚎𝚛) просматривается к получению из экземпляра (отношение экземпляр−класс)»

В нашем случае:
🔘 Объект 𝚘𝚋𝚓 является экземпляром класса 𝙱
🔘 При обращении к 𝚘𝚋𝚓.𝚊𝚝𝚝𝚛 𝙿𝚢𝚝𝚑𝚘𝚗 ищет атрибут в порядке 𝙼𝚁𝙾
🔘 Класс 𝙱 наследует от суперкласса 𝙰, поэтому 𝚊𝚝𝚝𝚛 = 𝟸 из класса 𝙰 становится доступным для экземпляров 𝙱
🔘 Атрибут 𝚊𝚝𝚝𝚛 = 𝟷 из метакласса 𝙼 недоступен для экземпляров класса 𝙱

«Если класс определяется с помощью метакласса, он должен передать имена, полученные из метакласса, используя наследование от суперкласса».

Поэтому код выводит 𝟸 — значение атрибута 𝚊𝚝𝚝𝚛 из суперкласса 𝙰.
Please open Telegram to view this post
VIEW IN TELEGRAM
Борис Пасхавер, «Pandas в действии», глава 𝟹:

«Pandas при сортировке ставит символы в верхнем регистре перед символами в нижнем. Таким образом, строка с заглавной буквы 𝚉 будет располагаться в очереди раньше строки со строчной буквы 𝚊».

В нашем случае:
− '𝙱𝚘𝚋' начинается с заглавной '𝙱'
− '𝙳𝚊𝚟𝚒𝚍' начинается с заглавной '𝙳'
− '𝚊𝚕𝚒𝚌𝚎' начинается со строчной '𝚊'
− '𝚌𝚑𝚊𝚛𝚕𝚒𝚎' начинается со строчной '𝚌'

Поэтому после сортировки порядок будет: сначала все строки с заглавными буквами (𝙱𝚘𝚋, 𝙳𝚊𝚟𝚒𝚍), затем со строчными (𝚊𝚕𝚒𝚌𝚎, 𝚌𝚑𝚊𝚛𝚕𝚒𝚎).

Для сортировки без учета регистра можно использовать параметр 𝚔𝚎𝚢 с функцией 𝚜𝚝𝚛.𝚕𝚘𝚠𝚎𝚛:

𝚍𝚏.𝚜𝚘𝚛𝚝_𝚟𝚊𝚕𝚞𝚎𝚜('𝙽𝚊𝚖𝚎', 𝚔𝚎𝚢=𝚕𝚊𝚖𝚋𝚍𝚊 𝚡: 𝚡.𝚜𝚝𝚛.𝚕𝚘𝚠𝚎𝚛())

Это даст естественный алфавитный порядок: ['𝚊𝚕𝚒𝚌𝚎', '𝙱𝚘𝚋', '𝚌𝚑𝚊𝚛𝚕𝚒𝚎', '𝙳𝚊𝚟𝚒𝚍'].
👍1👎1
🪤 Что выведет код?
Anonymous Quiz
28%
1
20%
2
29%
3
24%
Error
👎3👍1
В данной задаче рассматривается механизм наследования атрибутов от метаклассов. Код создает два метакласса 𝙼𝟷 и 𝙼𝟸 с атрибутами 𝚊𝚝𝚝𝚛𝟷 (со значениями 𝟷 и 𝟸 соответственно), затем определяет классы 𝙲𝟷 и 𝙲𝟸 с атрибутами 𝚊𝚝𝚝𝚛𝟷 (со значениями 𝟹 и 𝟺 соответственно), где 𝙲𝟸 наследует от 𝙲𝟷 и использует метакласс 𝙼𝟸. Ключевой момент заключается в том, что экземпляры классов НЕ наследуют атрибуты от метаклассов напрямую.

Марк Лутц, «Изучаем 𝙿𝚢𝚝𝚑𝚘𝚗», глава 𝟺𝟶:

«В действительности классы получают атрибуты метаклассов через свои ссылки __𝚌𝚕𝚊𝚜𝚜__ тем же самым способом, каким нормальные экземпляры наследуют их из классов через свои атрибуты __𝚌𝚕𝚊𝚜𝚜__, что имеет смысл, поскольку классы также являются экземплярами метаклассов».

Однако есть важное ограничение:

«Главное отличие состоит в том, что наследование экземпляров не проходит по ссылке __𝚌𝚕𝚊𝚜𝚜__ класса, но имеет ограниченный свой охват словарем __𝚍𝚒𝚌𝚝__ каждого класса в дереве согласно 𝙼𝚁𝙾 – следуя только __𝚋𝚊𝚜𝚎𝚜__ на уровне каждого класса и применяя ссылку __𝚌𝚕𝚊𝚜𝚜__ экземпляра только один раз.»

>>> 𝙸.𝚊𝚝𝚝𝚛𝟷
𝙰𝚝𝚝𝚛𝚒𝚋𝚞𝚝𝚎𝙴𝚛𝚛𝚘𝚛: '𝙲𝟸' 𝚘𝚋𝚓𝚎𝚌𝚝 𝚑𝚊𝚜 𝚗𝚘 𝚊𝚝𝚝𝚛𝚒𝚋𝚞𝚝𝚎 '𝚊𝚝𝚝𝚛𝟷'
# Хотя __𝚌𝚕𝚊𝚜𝚜__ класса нормально не проходит
# ошибку атрибутов: объект 𝙲𝟸 не имеет атрибута 𝚊𝚝𝚝𝚛𝟷»

Это происходит потому, что алгоритм наследования для экземпляров работает следующим образом:

𝟷. Если атрибут ищется в экземпляре, 𝙿𝚢𝚝𝚑𝚘𝚗 выполняет следующие шаги:
а) Выполняется поиск в __𝚍𝚒𝚌𝚝__ экземпляра.
б) Если не найдено, то ищется во всех классах в __𝚖𝚛𝚘__, найденном в __𝚌𝚕𝚊𝚜𝚜__ экземпляра.
в) Если не найдено, то ищется во всех классах в __𝚖𝚛𝚘__, найденном в __𝚌𝚕𝚊𝚜𝚜__ класса.
г) Если не найдено, то ошибка 𝙰𝚝𝚝𝚛𝚒𝚋𝚞𝚝𝚎𝙴𝚛𝚛𝚘𝚛.

В данном случае атрибут 𝚊𝚝𝚝𝚛𝟷 определен в нескольких местах: в метаклассах 𝙼𝟷 (значение 𝟷) и 𝙼𝟸 (значение 𝟸), а также в классах 𝙲𝟷 (значение 𝟹) и 𝙲𝟸 (значение 𝟺). При обращении к 𝙸.𝚊𝚝𝚝𝚛𝟷 𝙿𝚢𝚝𝚑𝚘𝚗 следует алгоритму наследования для экземпляров:

🔘 Сначала ищет в __𝚍𝚒𝚌𝚝__ экземпляра 𝙸 (не найдено)
🔘 Затем ищет в 𝙼𝚁𝙾 класса 𝙲𝟸: ['𝙲𝟸', '𝙲𝟷', '𝚘𝚋𝚓𝚎𝚌𝚝']
🔘 Находит 𝚊𝚝𝚝𝚛𝟷 в классе 𝙲𝟸 со значением 𝟺

Таким образом, код выведет 𝟺, поскольку экземпляр 𝙸 наследует атрибут 𝚊𝚝𝚝𝚛𝟷 от своего класса 𝙲𝟸, а не от метаклассов 𝙼𝟷 или 𝙼𝟸.
Please open Telegram to view this post
VIEW IN TELEGRAM
🤡3👍1👎1
🧩 Что выведет код?
Anonymous Quiz
16%
1
52%
2
20%
3
13%
Error
👍1👎1👏1🖕1
Код демонстрирует работу дескриптора не данных. Класс 𝙳 определяет только метод __𝚐𝚎𝚝__, но не определяет __𝚜𝚎𝚝__, что делает его дескриптором не данных.

Марк Лутц «Изучаем Python», глава 40:

«И наоборот, если этот дескриптор не определяет __𝚜𝚎𝚝__, то имя в словаре экземпляра скроет имя в классе согласно нормальному наследованию».

В коде происходит следующее:

🔘 Создается экземпляр 𝙸 класса 𝙲
🔘 При обращении к 𝙸.𝚍 вызывается метод __𝚐𝚎𝚝__ дескриптора 𝙳𝟸, выводится '__𝚐𝚎𝚝__'
🔘 В словарь экземпляра 𝙸.__𝚍𝚒𝚌𝚝__ добавляется ключ '𝚍' со значением '𝚜𝚙𝚊𝚖'
🔘 При повторном обращении к 𝙸.𝚍 имя '𝚍' в словаре экземпляра скрывает дескриптор в классе, поэтому выводится '𝚜𝚙𝚊𝚖'

>>> 𝙸.𝚍 # Доступ к унаследованному дескриптору не данных
__𝚐𝚎𝚝__
>>> 𝙸.__𝚍𝚒𝚌𝚝__['𝚍'] = '𝚜𝚙𝚊𝚖'
>>> 𝙸.𝚍 # Скрываем имя в классе согласно правилам нормального наследования экземпляров
'𝚜𝚙𝚊𝚖'

Это отличается от дескрипторов данных, которые перекрывают имена в словаре экземпляра благодаря наличию метода __𝚜𝚎𝚝__.
Please open Telegram to view this post
VIEW IN TELEGRAM
🤡2👍1👎1
🧩 Что выведет код?
Anonymous Quiz
56%
A.x <class '__main__.B'>
20%
A.x
13%
None
11%
Error
👍2👎1
Данный код демонстрирует работу методов метаклассов. Класс 𝙰 наследуется от 𝚝𝚢𝚙𝚎, что делает его метаклассом. Класс 𝙱 создается с использованием метакласса 𝙰 через синтаксис 𝚖𝚎𝚝𝚊𝚌𝚕𝚊𝚜𝚜=𝙰.

Марк Лутц «Изучаем Python», глава 40:

🔘 «Методы метакласса можно вызывать как обычные методы экземпляров, но они получают экземпляр метакласса — сам класс»
🔘 «Метод класса: передается экземпляр класса, не экземпляр самого класса. Метод метакласса: передается сам класс»

В данном случае:
🔘 Метод 𝚡 определен в метаклассе 𝙰
🔘 При вызове 𝙱.𝚡() метод получает сам класс 𝙱 как аргумент 𝚌𝚕𝚜
🔘 Функция 𝚙𝚛𝚒𝚗𝚝 выводит строку '𝙰.𝚡' и представление класса 𝙱 в виде <𝚌𝚕𝚊𝚜𝚜 '__𝚖𝚊𝚒𝚗__.𝙱'>

Методы метаклассов предназначены для управления данными уровня класса и доступны непосредственно на уровне класса без необходимости явного объявления ссылок.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2👎2
🪤 Что выведет код?
Anonymous Quiz
3%
Ni!
8%
Ni!Ni!
71%
Ni!Ni!Ni!Ni!
18%
Error
В данном коде демонстрируется ручное расширение класса — добавление нового метода к классу после его создания.

Принцип работает, потому что методы всегда можно присваивать классу после того, как он был создан. До тех пор пока присваиваемые методы являются функциями с дополнительным первым аргументом для получения нового экземпляра 𝚜𝚎𝚕𝚏».

Разберем выполнение кода по шагам:

🔘 Создается класс 𝙲𝚕𝚒𝚎𝚗𝚝𝟷 с конструктором, который принимает 𝚟𝚊𝚕𝚞𝚎 и сохраняет его в атрибут экземпляра
🔘 Определяется функция 𝚎𝚐𝚐𝚜𝚏𝚞𝚗𝚌(𝚘𝚋𝚓), которая принимает объект и возвращает 𝚘𝚋𝚓.𝚟𝚊𝚕𝚞𝚎 ∗ 𝟺
🔘 Происходит присваивание 𝙲𝚕𝚒𝚎𝚗𝚝𝟷.𝚎𝚐𝚐𝚜 = 𝚎𝚐𝚐𝚜𝚏𝚞𝚗𝚌 — функция становится методом класса
🔘 Создается экземпляр 𝚇 = 𝙲𝚕𝚒𝚎𝚗𝚝𝟷('𝙽𝚒!'), где 𝚟𝚊𝚕𝚞𝚎 становится '𝙽𝚒!'
🔘 Вызывается 𝚇.𝚎𝚐𝚐𝚜()

При вызове 𝚇.𝚎𝚐𝚐𝚜() происходит следующее:
− Python автоматически передает экземпляр 𝚇 как первый аргумент в функцию 𝚎𝚐𝚐𝚜𝚏𝚞𝚗𝚌
− Функция получает 𝚘𝚋𝚓 = 𝚇, где 𝚇.𝚟𝚊𝚕𝚞𝚎 = '𝙽𝚒!'
− Выполняется 𝚛𝚎𝚝𝚞𝚛𝚗 𝚘𝚋𝚓.𝚟𝚊𝚕𝚞𝚎 ∗ 𝟺, что дает '𝙽𝚒!' ∗ 𝟺 = '𝙽𝚒!𝙽𝚒!𝙽𝚒!𝙽𝚒!'

Данный аргумент может использоваться для обращения к информации о состоянии, доступной из экземпляра класса, хотя функции определены независимо от класса.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🫡1