Aspiring Data Science
366 subscribers
420 photos
11 videos
10 files
1.85K links
Заметки экономиста о программировании, прогнозировании и принятии решений, научном методе познания.
Контакт: @fingoldo

I call myself a data scientist because I know just enough math, economics & programming to be dangerous.
Download Telegram
#python #codegems

Встроенная функция property часто используется как декоратор, но в действительности она является классом. В Python функции и классы нередко взаимозаменяемы, поскольку являются вызываемыми объектами и не существует оператора new для создания объекта, поэтому вызов конструктора ничем не отличается от вызова фабричной функции. Вот полная сигнатура конструктора класса property: property(fget=None, fset=None, fdel=None, doc=None).

Функция vars не умеет работать с классами, в которых определен атрибут slots и нет атрибута dict (в отличие от функции dir, которая справляется с такими экземплярами).
Без аргумента vars() делает то же самое, что locals(): возвращает словарь, описывающий локальную область видимости.

Метод getattr всегда вызывается после getattribute и только в том случае, когда getattribute возбуждает исключение AttributeError. Чтобы при
получении атрибутов obj не возникало бесконечной рекурсии, в реализации getattribute следует использовать super().getattribute(obj, name).

Встроенный тип type на самом деле является метаклассом – классом по умолчанию для определенных пользователем классов.

В способе обработки атрибутов в Python существует важная асимметрия. При чтении атрибута через экземпляр обычно возвращается атрибут, определенный в этом экземпляре, а если такого атрибута в экземпляре не существует, то атрибут класса. С другой стороны, в случае присваивания атрибуту экземпляра обычно создается атрибут в этом экземпляре, а класс вообще никак не затрагивается. Эта асимметрия распространяется и на дескрипторы, в результате чего образуются две категории дескрипторов, различающиеся наличием или отсутствием метода set. Если set присутствует, то класс является переопределяющим дескриптором, иначе непереопределяющим.

Требование явно объявлять self первым аргументом методов – одно из противоречивых проектных решений в Python.Простота – даже элегантность – реализации достигается за счет пользовательского интерфейса: сигнатура метода – def zfill(self, width) – визуально не соответствует его вызову – label.zfill(8).

Метапрограммирование классов – это искусство создания или настройки классов во время выполнения. Классы в Python – полноправные объекты, поэтому функция может в любой момент создать новый класс, не используя ключевое слово class. Декораторы классов – также функции, которые дополнительно умеют инспектировать и изменять декорированный класс и даже заменять его другим. Наконец, метаклассы – самое продвинутое средство метапрограммирования классов: они позволяют создавать целые категории классов со специальными характеристиками.

Обычно мы воспринимаем type как функцию, которая возвращает класс объекта, потому что именно это делает выражение type(my_object): возвращает my_object.class.
Однако type – это класс, который создает новый класс, если вызывается с тремя аргументами. Рассмотрим следующий простой класс:
class MyClass(MySuperClass, MyMixin):
x = 42
def x2(self):
return self.x * 2

С помощью конструктора type мы можем создать MyClass во время выполнения:
MyClass = type('MyClass',
(MySuperClass, MyMixin),
{'x': 42, 'x2': lambda self: self.x * 2},
)

Этот вызов type функционально эквивалентен предыдущему предложению
блока class MyClass.
1🔥1
#python #codegems

Дескрипторы – это способ повторного использования одной и той же логики доступа в нескольких атрибутах. Например, типы полей в объектно-ориентированных отображениях вроде Django ORM и SQL Alchemy – дескрипторы, управляющие потоком данных от полей в записи базы данных к атрибутам Python-объекта и обратно. Дескриптор – это класс, который реализует динамический протокол, содержащий методы get, set и delete. Класс property реализует весь протокол дескриптора.

Пример использования дескриптора:
class Quantity:
def __set_name__(self, owner, name):
self.storage_name = name
def __set__(self, instance, value):
if value > 0:
instance.__dict__[self.storage_name] = value
else:
msg = f'{self.storage_name} must be > 0'
raise ValueError(msg)
# __get__ не нужен
class LineItem:
weight = Quantity()
price = Quantity()
def __init__(self, description, weight, price):
self.description = description
self.weight = weight
self.price = price
def subtotal(self):
return self.weight * self.price


Глядя на пример, можно подумать, что кода слишком много для управления всего-то парой атрибутов, но важно понимать, что логика дескриптора теперь вынесена в отдельную кодовую единицу: класс Quantity. Обычно мы не определяем дескриптор в том же модуле, в каком он используется, а заводим отдельный служебный модуль, предназначенный для использования во всем приложении, а то и во многих приложениях, если разрабатывается библиотека или фреймфорк.

Воображаемый магазин натуральных пищевых продуктов столкнулся с неожиданной проблемой: каким-то образом была создана строка заказа с пустым описанием, и теперь заказ невозможно выполнить. Чтобы предотвратить такие инциденты в будущем, мы создадим новый дескриптор, NonBlank. Проектируя NonBlank, мы обнаруживаем, что он очень похож на дескриптор Quantity, а отличается только логика проверки. Это наводит на мысль о рефакторинге и заведении двух базовых классов: завести абстрактный класс Validated, переопределяющий метод set, вызывая метод validate, который должен быть реализован в подклассах. Затем мы переписываем Quantity и реализуем NonBlank, наследуя классу Validated, так что остается лишь написать методы validate. Соотношение между классами Validated, Quantity и NonBlank – пример паттерна проектирования Шаблонный метод, который в классической книге «Паттерны проектирования» описывается следующим образом: Шаблонный метод определяет алгоритм в терминах абстрактных операций, которые переопределяются в подклассах для обеспечения конкретного поведения.

import abc
class Validated(abc.ABC):
def __set_name__(self, owner, name):
self.storage_name = name
def __set__(self, instance, value):
value = self.validate(self.storage_name, value)
instance.__dict__[self.storage_name] = value
@abc.abstractmethod
def validate(self, name, value):
"""вернуть проверенное значение или возбудить ValueError"""

class Quantity(Validated):
"""число, большее нуля"""
def validate(self, name, value):
if value <= 0:
raise ValueError(f'{name} must be > 0')
return value
class NonBlank(Validated):
"""строка, содержащая хотя бы один символ, отличный от пробела"""
def validate(self, name, value):
value = value.strip()
if not value:
raise ValueError(f'{name} cannot be blank')
return value

import model_v5 as model
class LineItem:
description = model.NonBlank()
weight = model.Quantity()
price = model.Quantity()
def __init__(self, description, weight, price):
self.description = description
self.weight = weight
self.price = price
def subtotal(self):
return self.weight * self.price
#python #fun

Goose Typing
😁1
#python #books

Ссылки на посты по книжке "Л. Рамальо. Python – к вершинам мастерства: Лаконичное и эффективное программирование" (в оригинале - Fluent Python, 2nd Edition). Содержат материал, который показался мне интересным и вошёл в категорию #codegems.

Затрагиваются механизмы сопоставления (match), классы данных и их аналоги, аннотирование типами, инструменты itertools, работа с классами/ООП, генераторы, контекстные менеджеры, асинхронка, дескрипторы классов.

Пробегитесь по темам, если есть незнакомые слова, возможно, есть смысл перечитать актуальную доку Питон )

1. [], {} и ()/match/ChainMap/MappingProxyType
2. class init/dict/json
3. unicode: NFC/NDF, strxfrm/NamedTuple/dataclass
4. more dataclass/typehints
5. weakrefs/functional programming/more typehints
6. Any/|/TypeVar/TypeAlias/typing.Protocol
7. positional-only/closures/singledispath/decorator via class
8. getattr/reduce via initializer/zip,zip_longest/principle of failing fast
9. goose typing/vurtual subclass/Hashable/ABC/Decimal
10. UserDict, UserList, UserString/MRO/mixin/get_annotations
11. (sub)generator/coprogram/type: ignore/with/@contextmanager
12. else in for,while,try/scientific sins/GIL/getswitchinterval/asyncio
13. asyncio.to_thread/asyncpg/asyncio.Semaphore/async with/keyword.iskeyword
14. property/vars/metaprogramming
15. class descriptors

Если решите читать книгу - ТОЛЬКО в оригинале, русский перевод плох.
1
#python #debugging #ic #icecream

from icecream import ic

# Using ic() to debug
ic(add(10, 20))
ic(add(30, 40))


ic| add(10, 20): 30
ic| add(30, 40): 70


ic.disable()  # Disables ic()
ic(multiply(3, 3)) # Prints nothing

ic.enable() # Re-enables ic()
ic(multiply(3, 3)) # Output: ic| multiply(3, 3): 9


def log_to_file(text):
with open("debug.log", "a") as f:
f.write(text + "\n")

ic.configureOutput(prefix="DEBUG| ", outputFunction=log_to_file)

ic(multiply(7, 7))


https://medium.com/pythoneers/debugging-in-python-replace-print-with-ic-and-do-it-like-a-pro-18f330c863cb
1
#python #typing

Про Final не знал. Self, TypeAlias, Literal заслуживают внимания.
На самом деле всё ещё сложнее с TypeVar.

https://medium.com/techtofreedom/8-levels-of-using-type-hints-in-python-a6717e28f8fd
👀1
#python #security #pypi

"Проблема возникла из-за удаления зависимости msgspec-python313-pre из репозитория PyPI (Python Package Index), который содержит тысячи сторонних модулей для Python. Злоумышленники добавили в репозиторий вредоносный пакет с тем же именем, который даёт им возможность удалённого выполнения произвольного кода на уязвимых системах, что может привести к компрометации данных, краже информации и полному контролю над заражённым ПК."

https://3dnews.ru/1119504/millioni-kompyuterov-okazalis-pod-ugrozoy-vzloma-izza-kriticheskoy-uyazvimosti-svyazannoy-s-python
#python #codegems

Как узнать, кто тянет вас на дно?! )

python -X importtime -c "from mymodule import *" 2>import_times.txt