15

我最近一直在使用 python 3.7,并正在寻找利用新数据类的方法。基本上我有一个迭代数据类字段并检查它们是否具有默认值的方法:

from dataclasses import fields, MISSING

@classmethod
def from_json(cls)
    datacls_fields = fields(cls)
    for field in datacls_fields:
        if  (field.default != MISSING):
            #...

但是在官方文档中,它说:

MISSING 值是一个标记对象,用于检测是否提供了 default 和 default_factory 参数。使用此标记是因为 None 是默认值的有效值。任何代码都不应直接使用 MISSING 值。

任何人都知道更好/更pythonic的方式来做到这一点?

4

2 回答 2

4

这是MISSING在python源代码中的定义dataclasses.py

# A sentinel object to detect if a parameter is supplied or not.  Use
# a class to give it a better repr.
class _MISSING_TYPE:
    pass
MISSING = _MISSING_TYPE()

定义很清楚,它的用例只是检查是否提供了参数,并区分了值None和未提供的值:

def my_func(a=MISSING):
    if a is not MISSING:
        # a value has been supplied, whatever his value

因此,在您的代码中使用它进行值比较是完全可以的。通过告诉No code 应该直接使用 MISSING 值,他们只是警告我们这个变量没有特定用途(其他用于比较)并且不应该在代码中使用以避免意外行为。

您应该更新您的代码以使用更 Pythonic 的语法is not MISSING

from dataclasses import fields, MISSING

@classmethod
def from_json(cls)
    datacls_fields = fields(cls)
    for field in datacls_fields:
        if field.default is not MISSING:

于 2020-08-25T15:33:33.473 回答
1

我认为 pythonic 解决方案依赖于使用魔法__dict__(文档:https ://docs.python.org/3/library/stdtypes.html#object.__dict__ )。

class Foo:
def __init__(self, a=1, b=2, c=3):
    self.a = a
    self.b = b
    self.c = c

x = Foo()
y = Foo(a=5)
print(x.__dict__ == Foo().__dict__)  # True
print(y.__dict__ == Foo().__dict__)  # False

基本上,当在对象实例上使用时,它会返回字段-值对(键值)的字典。

为了检查这些是否为默认值,我只需将给定实例上的这个字典与在默认无名对象上创建的相同字典进行比较。

该代码可能更具解释性。

PS这是所有字段是否都有默认值的答案。如果您需要确切哪些字段没有默认值的信息,这是我提出的解决方案(基于与上述相同的逻辑,但不是比较字典是否相等,而是找出它们之间的区别):

# Need the actual fields back?
x_dict = x.__dict__
y_dict = y.__dict__
default = Foo().__dict__
print(dict(set(x_dict.items()) - set(default.items())))
print(dict(set(y_dict.items()) - set(default.items())))

使用此代码时的输出:

{}
{'a': 5}

请参阅如何在 Python 中获取两个字典之间的区别?有关如何查找两个字典之间差异的更多信息。

于 2020-08-30T22:01:29.783 回答