Size: 2317
Comment:
|
Size: 9393
Comment:
|
Deletions are marked like this. | Additions are marked like this. |
Line 5: | Line 5: |
* В [[py3doc:datamodel#metaclasses|справочнике]] | * В [[py3ref:datamodel#metaclasses|справочнике]] * Внезапно развёрнутое описание [[https://stackoverflow.com/questions/100003/what-are-metaclasses-in-python?rq=1|на StackOverflow]] ([[https://habr.com/ru/post/145835/|перевод на Хабре]]) * [[https://sahandsaba.com/python-classes-metaclasses.html|Статья Sahand Saba]] ([[https://ru.hexlet.io/blog/posts/prodvinutyy-python-chast-3-klassy-i-metaklassy|перевод]]) * Забойная статья [[https://breadcrumbscollector.tech/when-to-use-metaclasses-in-python-5-interesting-use-cases/|Sebastian Buczyński]] 2020 года ([[https://webdevblog.ru/kogda-ispolzovat-metaklassy-v-python-5-interesnyh-variantov-ispolzovaniya/|Перевод]]) |
Line 7: | Line 10: |
Хороший пример real-life кода на Python, эксплуатирующий метаклассы и многое другое: [[py3doc:enum]] (в частности, [[py3doc:enum.html#how-are-enums-different|How are Enums different?]]) * Класс можно создать просто функцией (а можно и декоратором) |
Хороший пример real-life кода на Python, эксплуатирующий метаклассы и многое другое: * [[py3doc:enum]] (в частности, [[py3doc:enum.html#how-are-enums-different|How are Enums different?]]) * [[py3doc:abc]] Итак. * Класс можно создать просто функцией (aka [[WP:Monkey patch]]) * Декоратором |
Line 44: | Line 52: |
[[py3doc:datamodel#metaclasses|Подробности]]: | [[py3ref:datamodel#metaclasses|Подробности]]: |
Line 46: | Line 54: |
* * определённые правила для [[py3ref:datamodel.html#object.__init__|__init__()]] и [[py3ref:datamodel.html#object.__new__|__new__()]] |
* `__new__()` * ''создаёт'' экземпляр объекта (а `__init__()` заполняет готовый) * это метод класса (такой `@classmethod` без декоратора) * в нём можно поменять всё, что в `__init__()` приезжает готовое и read-only: `__slots__`, имя класса (если это метакласс) и т. п. Два примера: * Ненаследуемый класс {{{#!python class final(type): def __new__(metacls, name, parents, namespace): for cls in parents: if isinstance(cls, final): raise TypeError(f"{cls.__name__} is final") return super(final, metacls).__new__(metacls, name, parents, namespace) class E(metaclass=final): pass class C: pass class A(C, E): pass }}} * Синглтон (больше синглтонов [[https://webdevblog.ru/realizaciya-shablona-singleton-v-python/|тут]]) {{{#!python class Singleton(type): _instance = None def __call__(cls, *args, **kw): if not cls._instance: cls._instance = super(Singleton, cls).__call__(*args, **kw) return cls._instance |
Line 49: | Line 80: |
<!> Не путать с наследованием! | class S(metaclass=Singleton): A = 3 s, t = S(), S() s.newfield = 100500 print(f"{s.newfield=}, {t.newfield=}") print(f"{s is t=}") }}} * Модуль [[py3doc:types]] == Аннотации == Duck typing: * Экономия кода на описаниях и объявлениях типа * Экономия (несравненно бо́льшая) кода на всех этих ваших полиморфизмах * ⇒ Компактный читаемый код, хорошее отношение семантика/синтаксис * ⇒ Быстрое решение Д/З ☺ Однако: * Практически все ошибки — runtime * Много страданий от невнимательности (передал объект не того типа, и не заметил, пока не свалилось) * Вашей невнимательности не поможет даже хитрое IDE: оно ''тоже'' не знает о том, какого типа объекты правильные, какого — нет * (соответственно, о полях вашего объекта тоже) * Часть ''прагматики'' растворяется в коде (например, вы написали ''строковую'' функцию, как об этом узнать?) * Большие и сильно разрозненные проекты — ? Поэтому нужны указания о типе полей классов, параметрах и возвращаемых значений функций/методов и т. п. — [[py3tut:controlflow#function-annotations|Аннотации]] * Пример аннотаций полей, параметров и возвращаемых значений {{{#!python class C: A: int = 2 def __init__(self, param: int = None, signed: bool = True): if param != None: self.A = param if signed else abs(param) def mult(self, mlt) -> str: return self.A * mlt a, b = C(3), C("QWE") print(f"{a.mult([2])=}, {b.mult(2)=}") print(f"{a.__annotations__=}") print(f"{a.mult.__annotations__=}") print(f"{C.__init__.__annotations__}") }}} * Аннотации сами по себе не влияют на семантику функции * Типы в аннотациях — это ''настоящие'' типы * Про аннотацию переменных [[https://dzone.com/articles/new-in-python-syntax-for-variable-annotations|на DZone]] ([[https://tproger.ru/translations/python-variable-annotations/|перевод на tproger]]) === Составные и нечёткие типы === Python 3.9 с нами :):: Просто прочитаем [[https://docs.python.org/3/whatsnew/3.9.html|What’s New In Python 3.9]] * [[https://docs.python.org/3/whatsnew/3.9.html#type-hinting-generics-in-standard-collections|в частности, дженерики]] ([[pep:pep-0585]]) * Для указания, какого типа, например, ''элементы'' списка * `list[int]` в 3.9 vs. 3.8 Модуль [[py3doc:typing]] * Алиасы (практически `typedef`), `Any`, `NewType` (категоризация), `Callable` * Дженерики и [[py3doc:collections.abc]] * Инструменты: `NoReturn`, `Union`, `Optional`, `Type` (если сама переменная — класс), `Literal`, `Final`, … Отложенная аннотация: [[pep:pep-0563]] * [[https://habr.com/ru/company/lamoda/blog/432656/|Развесистая статья на Хабре]] (⩽ Python3.8, однако ☺, см [[pep:pep-0585]]) * [[https://habr.com/ru/company/lamoda/blog/435988/|Её продолжение]] * [[py3doc:dataclass]] — типизированные структуры * [[https://habr.com/ru/post/415829/|тот же автор на Хабре]] === MyPy === Зачем аннотации? * Дисциплина программирования * большие, сверхбольшие и «долгие» проекты * ''Потенциально'' возможные проверки (как в [[py3doc:dataclass]]) * Прагматика, включенная в синтаксис языка [[http://www.mypy-lang.org]]: ''статическая'' типизация в Python (ну, почти… или ''совсем''!) * --(Описание типов переменных, параметров и т. п.)--- * Проверка выражений с типизированными данными * В т. .ч ''не''-проверка нетипизиварованных * ''Компиляция''? * Bleedng edge: [[https://github.com/mypyc/mypyc|было]], [[https://github.com/python/mypy/tree/master/mypyc|стало]] Пример для `mypyc` {{{#!python import time from typing import Tuple def fb(x:int,y:int)->Tuple[int,int]: return y,x+y def test()->float: x:int=0 y:int=1 t:float=time.time() for i in range(1000000): x = 0 y = 1 for j in range(100): x,y=fb(x,y) return time.time()-t }}} == Д/З == '''TODO''' |
Метаклассы и аннотации
Это две совсем разные темы, если что).
Метаклассы
Внезапно развёрнутое описание на StackOverflow (перевод на Хабре)
Забойная статья Sebastian Buczyński 2020 года (Перевод)
Хороший пример real-life кода на Python, эксплуатирующий метаклассы и многое другое:
enum (в частности, How are Enums different?)
Итак.
Класс можно создать просто функцией (aka Monkey patch)
- Декоратором
- От класса можно унаследоваться и всё модифицировать в потомке
TODO but why then?
Создание класса с помощью type(name, bases, dict)
это вырожденный вызов type("имя", (кортеж родителей), {пространство имён})
1 C = type("C", (), {})
- Например,
Но type — это просто класс такой ⇒ от него можно унаследоваться, например, перебить ему __init__():
а вот это Boo = overtype… можно записать так:
(по сути, class C: — это class C(metaclass=type):)
__call__() → (__prepare__() для автоматического создания пространства имён, если есть), __new__(), __init__()
__new__()
создаёт экземпляр объекта (а __init__() заполняет готовый)
это метод класса (такой @classmethod без декоратора)
в нём можно поменять всё, что в __init__() приезжает готовое и read-only: __slots__, имя класса (если это метакласс) и т. п.
Два примера:
- Ненаследуемый класс
1 class final(type): 2 def __new__(metacls, name, parents, namespace): 3 for cls in parents: 4 if isinstance(cls, final): 5 raise TypeError(f"{cls.__name__} is final") 6 return super(final, metacls).__new__(metacls, name, parents, namespace) 7 class E(metaclass=final): pass 8 class C: pass 9 class A(C, E): pass
Синглтон (больше синглтонов тут)
1 class Singleton(type): 2 _instance = None 3 def __call__(cls, *args, **kw): 4 if not cls._instance: 5 cls._instance = super(Singleton, cls).__call__(*args, **kw) 6 return cls._instance 7 8 class S(metaclass=Singleton): 9 A = 3 10 s, t = S(), S() 11 s.newfield = 100500 12 print(f"{s.newfield=}, {t.newfield=}") 13 print(f"{s is t=}")
Модуль types
Аннотации
Duck typing:
- Экономия кода на описаниях и объявлениях типа
- Экономия (несравненно бо́льшая) кода на всех этих ваших полиморфизмах
- ⇒ Компактный читаемый код, хорошее отношение семантика/синтаксис
- ⇒ Быстрое решение Д/З ☺
Однако:
- Практически все ошибки — runtime
- Много страданий от невнимательности (передал объект не того типа, и не заметил, пока не свалилось)
Вашей невнимательности не поможет даже хитрое IDE: оно тоже не знает о том, какого типа объекты правильные, какого — нет
- (соответственно, о полях вашего объекта тоже)
Часть прагматики растворяется в коде (например, вы написали строковую функцию, как об этом узнать?)
- Большие и сильно разрозненные проекты — ?
Поэтому нужны указания о типе полей классов, параметрах и возвращаемых значений функций/методов и т. п. — Аннотации
- Пример аннотаций полей, параметров и возвращаемых значений
1 class C: 2 A: int = 2 3 def __init__(self, param: int = None, signed: bool = True): 4 if param != None: 5 self.A = param if signed else abs(param) 6 7 def mult(self, mlt) -> str: 8 return self.A * mlt 9 10 a, b = C(3), C("QWE") 11 print(f"{a.mult([2])=}, {b.mult(2)=}") 12 print(f"{a.__annotations__=}") 13 print(f"{a.mult.__annotations__=}") 14 print(f"{C.__init__.__annotations__}")
- Аннотации сами по себе не влияют на семантику функции
Типы в аннотациях — это настоящие типы
Про аннотацию переменных на DZone (перевод на tproger)
Составные и нечёткие типы
- Python 3.9 с нами :)
Просто прочитаем What’s New In Python 3.9
в частности, дженерики (pep-0585)
Для указания, какого типа, например, элементы списка
list[int] в 3.9 vs. 3.8
Модуль typing
Алиасы (практически typedef), Any, NewType (категоризация), Callable
Дженерики и collections.abc
Инструменты: NoReturn, Union, Optional, Type (если сама переменная — класс), Literal, Final, …
Отложенная аннотация: pep-0563
Развесистая статья на Хабре (⩽ Python3.8, однако ☺, см pep-0585)
dataclass — типизированные структуры
MyPy
Зачем аннотации?
- Дисциплина программирования
- большие, сверхбольшие и «долгие» проекты
Потенциально возможные проверки (как в dataclass)
- Прагматика, включенная в синтаксис языка
http://www.mypy-lang.org: статическая типизация в Python (ну, почти… или совсем!)
Описание типов переменных, параметров и т. п.-
- Проверка выражений с типизированными данными
В т. .ч не-проверка нетипизиварованных
Компиляция?
Пример для mypyc
Д/З
TODO