python - 如何在冻结的数据类自定义 __init__ 方法中设置属性?
问题描述
我正在尝试构建一个@dataclass
定义架构但实际上并未使用给定成员实例化的架构。(基本上,我@dataclass
为了其他目的劫持了方便的语法)。这几乎可以满足我的要求:
@dataclass(frozen=True, init=False)
class Tricky:
thing1: int
thing2: str
def __init__(self, thing3):
self.thing3 = thing3
但我得到了一个FrozenInstanceError
方法__init__
:
dataclasses.FrozenInstanceError: cannot assign to field 'thing3'
我需要frozen=True
(用于哈希性)。有什么方法可以在 freeze 中设置自定义属性__init__
吗@dataclass
?
解决方案
问题是默认__init__
实现object.__setattr__()
与冻结类一起使用,并且通过提供您自己的实现,您也必须使用它,这会使您的代码非常hacky:
@dataclass(frozen=True, init=False)
class Tricky:
thing1: int
thing2: str
def __init__(self, thing3):
object.__setattr__(self, "thing3", thing3)
不幸的是,python 没有提供使用默认实现的方法,因此我们不能简单地执行以下操作:
@dataclass(frozen=True, init=False)
class Tricky:
thing1: int
thing2: str
def __init__(self, thing3, **kwargs):
self.__default_init__(DoSomething(thing3), **kwargs)
但是,我们可以很容易地实现该行为:
def dataclass_with_default_init(_cls=None, *args, **kwargs):
def wrap(cls):
# Save the current __init__ and remove it so dataclass will
# create the default __init__.
user_init = getattr(cls, "__init__")
delattr(cls, "__init__")
# let dataclass process our class.
result = dataclass(cls, *args, **kwargs)
# Restore the user's __init__ save the default init to __default_init__.
setattr(result, "__default_init__", result.__init__)
setattr(result, "__init__", user_init)
# Just in case that dataclass will return a new instance,
# (currently, does not happen), restore cls's __init__.
if result is not cls:
setattr(cls, "__init__", user_init)
return result
# Support both dataclass_with_default_init() and dataclass_with_default_init
if _cls is None:
return wrap
else:
return wrap(_cls)
接着
@dataclass_with_default_init(frozen=True)
class DataClass:
value: int
def __init__(self, value: str):
# error:
# self.value = int(value)
self.__default_init__(value=int(value))
更新:我打开了这个错误,我希望在 3.9 之前实现它。
推荐阅读
- rest - 二进制数据的 API 设计
- php - Laravel cursorPaginate 没有可见的 ID 字段。(InvalidArgumentException 非法运算符和值组合。)
- flutter - 如何制作一个显示选项列表的 IconButton
- ruby-on-rails - 如何在rails中使用assert_selector获取占位符值
- c - pthread_key_create 会导致内存泄漏吗?
- android - 无法为改造 2 调用无参数构造函数。调用 MVVM 协程改造
- javascript - 无法将子文本附加到元素
- hibernate - Hibernate detach 保留了在大型查询中导致 OutOfMemory 错误的急切子项
- python - 如何从这些字符串中提取数据?
- python - 您提供的 AWS 访问密钥 ID 不存在于我们的记录中。AWS