Как сгенерировать __slots__ на основе аннотаций в Python 3.8-3.14Python

Программы на Python
Ответить
Anonymous
 Как сгенерировать __slots__ на основе аннотаций в Python 3.8-3.14

Сообщение Anonymous »

Я хотел бы создавать классы на основе __slots__ без необходимости повторять имена атрибутов, которые я уже перечислил в аннотациях типов.
До Python 3.14 я мог сделать это:

Код: Выделить всё

class C:
foo: int
bar: int
__slots__ = (*__annotations__,)
not_a_slot: ClassVar[str] = 'some class variable'
Однако Python 3.14 перешёл на аннотации с ленивой оценкой, а это означает, что когда приходит время назначить __slots__, словарь __annotations__ еще не существует. Собственные лучшие практики Python говорят, что в любом случае не следует использовать __annotations__ непосредственно после версии 3.10.

Код: Выделить всё

@dataclass(slots=True)
работает для Python 3.10 и более поздних версий (со множеством побочных эффектов). К сожалению, мой код предназначен для многих устаревших систем, поэтому он должен работать как на Python 3.8 , так и на Python 3.14, который есть на моем ноутбуке.
Есть ли совместимый с 3.8, но перспективный способ получить __slots__ на основе некоторого подмножества аннотированных атрибутов, но без повторения имен?
Единственное обходное решение, которое я нашел, - это сделать декоратор класса, который создает класс с установленным __slots__, таким образом:

Код: Выделить всё

from typing import ClassVar, get_origin

try:
from inspect import get_annotations
except ImportError:

def get_annotations(x):
return x.__annotations__

def annotations_to_slots(klass):
class Out(klass):
__slots__ = tuple(
name
for name, declared_type in get_annotations(klass).items()
if get_origin(declared_type) is not ClassVar
)

Out.__name__ = klass.__name__
try:
Out.__doc__ = klass.__doc__
except AttributeError:
pass
return Out

@annotations_to_slots
class C:
__slots__ = ()  # will be filled in by @annotations_to_slots
foo: int
bar: int
not_a_slot: ClassVar[str] = 'not a slot'

Кажется, это работает, но это некрасиво по нескольким причинам. __slots__ попадает в машинно-сгенерированный класс, а не в класс, который определил поле, определяющий класс должен включать __slots__ = (), что вводит в заблуждение даже при наличии комментария, а дополнительный класс в MRO делает наследование менее очевидным.
Есть ли лучший подход?

Подробнее здесь: https://stackoverflow.com/questions/798 ... n-3-8-3-14
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Python»