Как показать код, сгенерированный при использовании декоратора класса @dataclass?

Python 3.7 представляет модуль dataclasses, который содержит декоратор @dataclass. Этот декоратор может генерировать функции класса. Как я могу распечатать эти сгенерированные функции?


person OrangeTux    schedule 19.11.2018    source источник
comment
Нет простого пути. Вас может заинтересовать проект DataclassInspector, который пытается сделать именно это. Если вы хотите посмотреть, что на самом деле делают функции, вы можете использовать dis.dis   -  person Patrick Haugh    schedule 19.11.2018
comment
Вы все еще можете проверить сгенерированную подпись: str(inspect.signature(YourDataClass.__init__))   -  person x0s    schedule 29.11.2018
comment
Я отправил запрос функции github.com/ericvsmith/dataclasses/issues/139.   -  person pylang    schedule 30.11.2018


Ответы (2)


Я сам задавал тот же вопрос. Часть проекта Dataclasses должна иметь параметр verbose, но не .

Нашел это полезное видео. Судя по видео, dataclasses.py — это генератор кода. Так что это должно быть нашей первой идеей, как получить код.


Я пробовал этот код:

from dataclasses import dataclass
import inspect
import os
from uncompyle6 import PYTHON_VERSION, deparse_code2str

@dataclass
class C:
    name: str
    value: int = 34

inspect.getmembers(C) #('__init__', <function __init__(self, name: str, value: int = 34) -> None>)

co= C.__init__.__code__ # let's find out code for the __init__ method from code object

code = deparse_code2str(
                code=co,
                version=PYTHON_VERSION,
                out=open(os.devnull, "w"))
print(code)

Будет печатать

self.name = name
self.value = value

Код фактически использует инспектор для понимания класса, а затем для декомпиляции методов с помощью декомпилятора Python.

Вот обнаруженные методы:

def __eq__(self, other):
    if other.__class__ is self.__class__:
        return (self.name, self.value) == (
            other.name,
            other.value,
        )
    else:
        return NotImplemented

def __init__(self, name: str, value: int = 34) -> None:
    self.name = name
    self.value = value

def __repr__(self):
    key = (id(self), _thread.get_ident())
    if key in repr_running:
        return "..."
    else:
        repr_running.add(key)
        try:
            result = user_function(self)
        finally:
            repr_running.discard(key)

        return result

На самом деле существует проект, который выполняет обнаружение @dataclass. Я установил его, и он работал.

from dataclasses import dataclass
import inspect
import os
import dis
from DataclassInspector.inspector import Inspector

@dataclass
class C:
    name: str
    value: int = 34

inspected = Inspector(C)
print(inspected._generate_code())

При условии, что вывод выглядит следующим образом:

from dataclasses import Field, _MISSING_TYPE, _DataclassParams
class C:
    __dataclass_fields__ = {'name': "Field(name='name', type=str, default=_MISSING_TYPE, default_factory=_MISSING_TYPE, init=True, repr=True, hash=None, compare=True, metadata={}, _field_type=_FIELD)", 'value': "Field(name='value', type=int, default=34, default_factory=_MISSING_TYPE, init=True, repr=True, hash=None, compare=True, metadata={}, _field_type=_FIELD)"}
    __dataclass_params__ = _DataclassParams(init=True,repr=True,eq=True,order=False,unsafe_hash=False,frozen=False)
    name: str
    value: int = 34

    def __eq__(self, other):
        if other.__class__ is self.__class__:
            return (self.name, self.value) == (other.name, other.value)
        else:
            return NotImplemented


    __hash__ = None

    def __init__(self, name: str, value: int = 34) -> None:
        self.name = name
        self.value = value



    def __repr__(self):
        key = (
         id(self), _thread.get_ident())
        if key in repr_running:
            return '...'
        else:
            repr_running.add(key)
            try:
                result = user_function(self)
            finally:
                repr_running.discard(key)

            return result
person prosti    schedule 04.06.2019

После проверки реализации класса данных методы, похоже, сгенерированы dataclasses._create_fn. Чтобы получить исходный сгенерированный код, я издевался над функцией как:

import dataclasses

_original_create_fn = dataclasses._create_fn

def _new_create_fn(name, args, body, **kwargs):
    args_str = ', '.join(args)
    body_str = '\n'.join('  ' + l for l in body)
    print(f'def {name}({args_str}):\n{body_str}\n')
    return _original_create_fn(name, args, body, **kwargs)

dataclasses._create_fn = _new_create_fn


@dataclasses.dataclass
class A:
    x: int
    y: int

Которые отображают что-то вроде:

def __init__(self, x:_type_x, y:_type_y):
  self.x=x
  self.y=y

def __repr__(self):
  return self.__class__.__qualname__ + f"(x={self.x!r}, y={self.y!r})"

def __eq__(self, other):
  if other.__class__ is self.__class__:
   return (self.x,self.y,)==(other.x,other.y,)
  return NotImplemented
person Conchylicultor    schedule 23.04.2021