从 python `dataclass` `__repr__` 中排除默认字段

Ton*_*ock 7 python repr python-dataclasses

概括

我有dataclass10多个字段print()使用它们将有趣的上下文埋藏在默认值的墙中 - 让我们通过不再不必要地重复这些来使它们变得更友好。

Python 中的数据类

Python 的@dataclasses.dataclass()( PEP 557 ) 提供自动可打印表示 ( __repr__())。

假设这个例子,基于 python.org 的

from dataclasses import dataclass


@dataclass
class InventoryItem:
    name: str
    unit_price: float = 1.00
    quantity_on_hand: int = 0
Run Code Online (Sandbox Code Playgroud)

装饰器@dataclass(repr=True)(默认)将得到print()一个很好的输出:

InventoryItem(name='Apple', unit_price='1.00', quantity_on_hand=0)
Run Code Online (Sandbox Code Playgroud)

我想要的:跳过打印默认值

repr它会打印所有字段,包括您不想显示的隐含默认值。

print(InventoryItem("Apple"))

# Outputs: InventoryItem(name='Apple', unit_price='1.00', quantity_on_hand=0)
# I want: InventoryItem(name='Apple')
Run Code Online (Sandbox Code Playgroud)
print(InventoryItem("Apple", unit_price="1.05"))

# Outputs: InventoryItem(name='Apple', unit_price='1.05', quantity_on_hand=0)
# I want: InventoryItem(name='Apple', unit_price='1.05')
Run Code Online (Sandbox Code Playgroud)
print(InventoryItem("Apple", quantity_on_hand=3))

# Outputs: InventoryItem(name='Apple', unit_price=1.00, quantity_on_hand=3)
# I want: InventoryItem(name='Apple', quantity_on_hand=3)
Run Code Online (Sandbox Code Playgroud)
print(InventoryItem("Apple", unit_price='2.10', quantity_on_hand=3))

# Output is fine (everything's custom):
# InventoryItem(name='Apple', unit_price=2.10, quantity_on_hand=3)
Run Code Online (Sandbox Code Playgroud)

讨论

dataclass repr在内部,这是python 的 -generator机制3.10.4:->cls.__repr__=_repr_fn(flds, globals))_recursive_repr(fn)

@dataclass(repr=False)可能是关闭再def __repr__(self):添加的情况。

如果是这样,那会是什么样子?我们不想包含可选的默认值。

语境

重复一遍,在实践中,我的dataclass10 多个字段

print()通过运行代码和 repl 来获取实例,并@pytest.mark.parametrize使用-vvv.

大数据类的非默认值(有时是输入)是不可能看到的,因为它们被隐藏在默认字段中,更糟糕的是,每个非默认值都大得不成比例且令人分心:掩盖了打印的其他有价值的内容。

相关问题

截至今天,还没有太多dataclass问题(这可能会改变):

use*_*849 7

你可以这样做:

import dataclasses
from dataclasses import dataclass
from operator import attrgetter


@dataclass(repr=False)
class InventoryItem:
    name: str
    unit_price: float = 1.00
    quantity_on_hand: int = 0

    def __repr__(self):
        nodef_f_vals = (
            (f.name, attrgetter(f.name)(self))
            for f in dataclasses.fields(self)
            if attrgetter(f.name)(self) != f.default
        )

        nodef_f_repr = ", ".join(f"{name}={value}" for name, value in nodef_f_vals)
        return f"{self.__class__.__name__}({nodef_f_repr})"
        

# Prints: InventoryItem(name=Apple)
print(InventoryItem("Apple"))

# Prints: InventoryItem(name=Apple,unit_price=1.05)
print(InventoryItem("Apple", unit_price="1.05"))

# Prints: InventoryItem(name=Apple,unit_price=2.10,quantity_on_hand=3)
print(InventoryItem("Apple", unit_price='2.10', quantity_on_hand=3))
Run Code Online (Sandbox Code Playgroud)