简体   繁体   English

以编程方式扩展数据类'__repr__

[英]Extend dataclass' __repr__ programmatically

Suppose I have a dataclass with a set method.假设我有一个带有 set 方法的数据类。 How do I extend the repr method so that it also updates whenever the set method is called:如何扩展 repr 方法,以便在调用 set 方法时它也会更新:

from dataclasses import dataclass
@dataclass
class State:
    A: int = 1
    B: int = 2
    def set(self, var, val):
        setattr(self, var, val)

Ex:前任:

In [2]: x = State()

In [3]: x
Out[3]: State(A=1, B=2)

In [4]: x.set("C", 3)

In [5]: x
Out[5]: State(A=1, B=2)

In [6]: x.C
Out[6]: 3

The outcome I would like我想要的结果

In [7]: x
Out[7]: State(A=1, B=2, C=3)

The dataclass decorator lets you quickly and easily build classes that have specific fields that are predetermined when you define the class. dataclass装饰器使您可以快速轻松地构建具有特定字段的类,这些字段在您定义 class 时预先确定。 The way you're intending to use your class, however, doesn't match up very well with what dataclasses are good for.但是,您打算使用 class 的方式与数据类的用途不太匹配。 You want to be able to dynamically add new fields after the class already exists, and have them work with various methods (like __init__ , __repr__ and presumably __eq__ ).您希望能够在 class 已经存在之后动态添加新字段,并让它们使用各种方法(如__init____repr__和大概__eq__ )。 That removes almost all of the benefits of using dataclass .这几乎消除了使用dataclass的所有好处。 You should instead just write your own class that does what you want it to do.相反,您应该编写自己的 class 来执行您想要的操作。

Here's a quick and dirty version:这是一个快速而肮脏的版本:

class State:
    _defaults = {"A": 1, "B": 2}
    
    def __init__(self, **kwargs):
        self.__dict__.update(self._defaults)
        self.__dict__.update(kwargs)
        
    def __eq__(self, other):
        return self.__dict__ == other.__dict__ # you might want to add some type checking here
        
    def __repr__(self):
        kws = [f"{key}={value!r}" for key, value in self.__dict__.items()]
        return "{}({})".format(type(self).__name__, ", ".join(kws))

This is pretty similar to what you get from types.SimpleNamespace , so you might just be able to use that instead (it doesn't do default values though).这与您从types.SimpleNamespace获得的内容非常相似,因此您可能只能使用它(尽管它不执行默认值)。

You could add your set method to this framework, though it seems to me like needless duplication of the builtin setattr function you're already using to implement it.您可以将您的set方法添加到此框架中,但在我看来,这似乎是您已经用来实现它的内置setattr function 的不必要重复。 If the caller needs to dynamically set an attribute, they can call setattr themselves.如果调用者需要动态设置属性,可以自己调用setattr If the attribute name is constant, they can use normal attribute assignment syntax instead s.foo = "bar" .如果属性名称是常量,他们可以使用普通的属性赋值语法来代替s.foo = "bar"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM