Как удалить атрибуты класса данных - PullRequest
0 голосов
/ 26 сентября 2019

У меня есть такой класс данных:

@dataclass
class Bla:
    arg1: Optional[int] = None
    arg2: Optional[str] = None
    arg3: Optional[Dict[str, str]] = None

Я хочу это поведение:

>>> bla = Bla(arg1=None, arg2=None, arg3=None)
>>> asdict(bla)
{'arg1': None, 'arg2': None, 'arg3': None}

>>> bla = Bla()
{}

В этом конкретном случае я мог бы использовать dict, но я бы проигралвозможность иметь подсказки типа (и использовать mypy)

Итак, я попробовал это:

class none:
    ...

@dataclass
class Bla:
    arg1: Union[none, int] = none()
    arg2: Union[none, str] = none()
    arg3: Union[none, Dict[str, str]] = none()

    def __post_init__(self) -> None:
        for k, v in self.__dict__.copy().items():
            if isinstance(v, none):
                delattr(self, k)

Но результат был:

>>> asdict(Bla())
{'arg1': <__main__.none object at 0x7f71bc0159b0>, 'arg2': <__main__.none object at 0x7f71bc015a90>, 'arg3': <__main__.none object at 0x7f71bc015ac8>}

Я ожидал пустойdict

Если попытаться:

>>> a = Bla(None, None, None)
>>> del a.__dict__["arg1"]
>>> asdict(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/(....)/venv/lib/python3.6/site-packages/dataclasses.py", line 1011, in asdict
    return _asdict_inner(obj, dict_factory)
  File "/home/(...)/venv/lib/python3.6/site-packages/dataclasses.py", line 1018, in _asdict_inner
    value = _asdict_inner(getattr(obj, f.name), dict_factory)
AttributeError: 'Bla' object has no attribute 'arg1'

Как я могу динамически удалять атрибуты из объекта класса данных таким образом, чтобы я мог использовать asdict после этого?

1 Ответ

0 голосов
/ 27 сентября 2019

Это не ответ на ваш вопрос об удалении атрибутов из класса данных, но он предоставляет механизм для получения пользовательского asdict, который ведет себя так, как вы хотите:

from dataclasses import dataclass
from typing import Optional, Dict, cast

SENTINEL = cast(None, object())  # have a sentinel that pretends to be 'None'


@dataclass
class Bla:
    arg1: Optional[int] = SENTINEL
    arg2: Optional[str] = SENTINEL
    arg3: Optional[Dict[str, str]] = SENTINEL

    def asdict(self):
        return {k: v for k, v in self.__dict__.items() if v is not SENTINEL}

Некоторые тесты:

>>> Bla().asdict()
{}
>>> Bla(None, None).asdict()
{'arg1': None, 'arg2': None}
>>> Bla(1, 'foo', None).asdict()
{'arg1': 1, 'arg2': 'foo', 'arg3': None}

Но помните, что все это ложь, и атрибуты все еще существуют при явном вызове:

>>> print(Bla().arg1)
<object object at 0x7fc89ed84250>
...