@dataclass Python类中的拼写错误的字段

时间:2018-12-14 04:57:18

标签: python python-3.x python-dataclasses

如何在设置@dataclass装饰的Python类中设置拼写错误的字段时引发异常?

我想要一种实用的方法来做到这一点。我需要改写自己的装饰器吗?

@dataclass
class C(object):
    x: int = 1

obj = C()
obj.y = 2  # should raise an exception

3 个答案:

答案 0 :(得分:5)

一种简单的方法(与 any 类一起使用)是定义__slots__

In [1]: from dataclasses import dataclass

In [2]: @dataclass
   ...: class Foo:
   ...:     __slots__ = 'bar','baz'
   ...:     bar: int
   ...:     baz: int
   ...:

In [3]: foo = Foo(42, 88)

In [4]: foo.biz = 10
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-4-d52b60444257> in <module>()
----> 1 foo.biz = 10

AttributeError: 'Foo' object has no attribute 'biz'

广告位的目的是作为一个小的优化。它允许类的实例使用符号表代替dict作为类的命名空间。它可以略微提高属性访问的速度,并且可以显着提高每个实例的内存使用量(因为实例在底层不包含dict),但是,它不允许动态属性设置。

这实际上是我最喜欢的__slots__功能

请注意,至少在要让子类保留插槽行为的情况下,至少在对插槽使用继承时必须小心。

答案 1 :(得分:0)

一种方法是将数据类标记为frozen

>>> from dataclasses import dataclass
>>> @dataclass(frozen=True)
... class C:
...     x: int = 1
...     
>>> c = C()
>>> c.y = 1
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "<string>", line 3, in __setattr__
dataclasses.FrozenInstanceError: cannot assign to field 'y'

但是请注意,这会使所有现有属性(在这种情况下,例如x)也都是只读的。

答案 2 :(得分:0)

您可以提供自己的 __setattr__() 方法,该方法只允许分配给已知字段。

示例:

@dataclass
class C:
    x: int = 1

    def __setattr__(self, k, v): 
        if k not in self.__annotations__: 
            raise AttributeError(f'{self.__class__.__name__} dataclass has no field {k}')
        super().__setattr__(k, v)

然后失败/像这样工作:

[ins] In [3]: obj = C() 
         ...: obj.y = 2                                                                                                                                                                       
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-3-7a568eb098b1> in <module>
      1 obj = C()
----> 2 obj.y = 2

<ipython-input-2-d30972f86fbb> in __setattr__(self, k, v)
      5     def __setattr__(self, k, v):
      6         if k not in self.__annotations__:
----> 7             raise AttributeError(f'{self.__class__.__name__} dataclass has no field {k}')
      8         super().__setattr__(k, v)
      9 

AttributeError: C dataclass has no field y

[ins] In [4]: obj.x = 23                                                                                                                                                                      

[ins] In [5]: obj.x                                                                                                                                                                           
Out[5]: 23