So generieren Sie __slots__ basierend auf Annotationen in Python 3.8-3.14Python

Python-Programme
Anonymous
 So generieren Sie __slots__ basierend auf Annotationen in Python 3.8-3.14

Post by Anonymous »

Ich möchte __slots__-basierte Klassen erstellen, ohne die Attributnamen wiederholen zu müssen, die ich bereits in Typanmerkungen aufgeführt habe.
Vor Python 3.14 konnte ich Folgendes tun:

Code: Select all

class C:
foo: int
bar: int
__slots__ = (*__annotations__,)
not_a_slot: ClassVar[str] = 'some class variable'
Python 3.14 ist jedoch auf verzögert ausgewertete Annotationen umgestiegen, was bedeutet, dass bei der Zuweisung von __slots__ das Diktat __annotations__ noch nicht vorhanden ist. Pythons eigene Best Practices besagen, dass __annotations__ ohnehin nicht direkt nach 3.10 verwendet werden soll.

Code: Select all

@dataclass(slots=True)
funktioniert für Python 3.10 und höher (mit vielen Nebenwirkungen). Leider zielt mein Code auf viele Legacy-Systeme ab und muss daher sowohl auf Python 3.8 als auch auf 3.14 funktionieren, die ich auf meinem Laptop habe.
Gibt es eine 3.8-kompatible, aber zukunftssichere Möglichkeit, einen __slots__ zu erreichen, der auf einer Teilmenge annotierter Attribute basiert, aber ohne die Namen zu wiederholen?
Die einzige Problemumgehung, die ich habe Ich habe herausgefunden, dass ich einen Klassendekorator erstellen soll, der eine Klasse mit dem Satz __slots__ erstellt, also:

Code: Select all

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'

Das scheint zu funktionieren, ist aber aus mehreren Gründen hässlich. Die __slots__ landen in einer maschinell generierten Klasse und nicht in der Klasse, die das Feld definiert hat. Die definierende Klasse muss __slots__ = () enthalten, was selbst mit dem Kommentar irreführend ist, und die zusätzliche Klasse im MRO macht die Vererbung weniger offensichtlich.
Gibt es einen besseren Ansatz?

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post