<p>因此,不幸的是,<code>@property</code>语法总是被解释为对<code>uploaded_by</code>的赋值(因为它<em>是</em>)。<code>dataclass</code>机制将其解释为默认值,因此它将传递属性对象!这相当于:</p>
<pre><code>In [11]: import dataclasses
...:
...: @dataclasses.dataclass
...: class FileObject:
...: uploaded_by: str
...: _uploaded_by: str = dataclasses.field(repr=False, init=False)
...: def save(self):
...: print(self.uploaded_by)
...:
...: def _get_uploaded_by(self):
...: return self._uploaded_by
...:
...: def _set_uploaded_by(self, uploaded_by):
...: print('Setter Called with Value ', uploaded_by)
...: self._uploaded_by = uploaded_by
...: uploaded_by = property(_get_uploaded_by, _set_uploaded_by)
...: p = FileObject()
...: p.save()
Setter Called with Value <property object at 0x10761e7d0>
<property object at 0x10761e7d0>
</code></pre>
<p>基本上是这样的:</p>
<pre><code>In [13]: @dataclasses.dataclass
...: class Foo:
...: bar:int = 1
...: bar = 2
...:
In [14]: Foo()
Out[14]: Foo(bar=2)
</code></pre>
<p>我不认为有一个干净的方法可以解决这个问题,也许它可以被认为是一个bug,但实际上,不确定解决方案应该是什么,因为本质上,datalcass机制将对类主体中类型注释变量的任何赋值解释为创建的<code>__init__</code>的默认值。您可以使用<code>@property</code>语法的特殊情况,也可以只使用<code>property</code>对象本身,这样至少<code>@property</code>和<code>x = property(set_x, get_x)</code>的行为是一致的</p>
<p>需要明确的是,以下<em>类作品</em>:</p>
<pre><code>In [22]: import dataclasses
...:
...: @dataclasses.dataclass
...: class FileObject:
...: uploaded_by: str
...: _uploaded_by: str = dataclasses.field(repr=False, init=False)
...: @property
...: def uploaded_by(self):
...: return self._uploaded_by
...: @uploaded_by.setter
...: def uploaded_by(self, uploaded_by):
...: print('Setter Called with Value ', uploaded_by)
...: self._uploaded_by = uploaded_by
...:
...: p = FileObject(None)
...: print(p.uploaded_by)
Setter Called with Value None
None
In [23]: FileObject()
Setter Called with Value <property object at 0x1086debf0>
Out[23]: FileObject(uploaded_by=<property object at 0x1086debf0>)
</code></pre>
<p>但是请注意,您不能设置有用的默认值!它将永远占据这片土地。。。更糟糕的是,在我看来,如果你不想要一个默认值,它总是会创建一个</p>
<h3>编辑:找到了一个潜在的解决方法</h3>
<p>这应该是显而易见的,但是您可以在类上设置property对象</p>
<pre><code>import dataclasses
import typing
@dataclasses.dataclass
class FileObject:
uploaded_by:typing.Optional[str]=None
def _uploaded_by_getter(self):
return self._uploaded_by
def _uploaded_by_setter(self, uploaded_by):
print('Setter Called with Value ', uploaded_by)
self._uploaded_by = uploaded_by
FileObject.uploaded_by = property(
FileObject._uploaded_by_getter,
FileObject._uploaded_by_setter
)
p = FileObject()
print(p)
print(p.uploaded_by)
</code></pre>