Property for dataclass field with default value
Ivan Ivanyuk
ivan.ivanyuk at gmail.com
Wed Jun 17 09:21:30 EDT 2020
Hello All,
I have some trouble using @dataclass together with @property decorator
or property() function.
>From the documentation and PEP is seems that the intended behaviour of
@dataclass is to be the same as normal __init__() that sets instance
variables.
But it seems that when using @property decorator some parts work
differently when relying on default values. I'm using Pyhton 3.8.3 for
this.
Using the code:
from dataclasses import dataclass
@dataclass
class Container:
x: int = 30
@property
def x(self) -> int:
return self._x
@x.setter
def x(self, z: int):
if z > 1:
self._x = z
else:
raise ValueError
c= Container(x=10)
print(c)
c= Container()
print(c)
output is:
Container(x=10)
Traceback (most recent call last):
File "/Users/ivanivanyuk/Documents/Shared/repos/bitbucket/evbox/g5plus-automated-testing/dataclass_example.py",
line 18, in <module>
c= Container()
File "<string>", line 3, in __init__
File "/Users/ivanivanyuk/Documents/Shared/repos/bitbucket/evbox/g5plus-automated-testing/dataclass_example.py",
line 13, in x
if z > 1:
TypeError: '>' not supported between instances of 'property' and 'int'
Code with __init__() being inserted that should be roughly the same as
generated by the @dataclass decorator:
@dataclass
class Container:
x: int = 30
def __init__(self, x:int = 30):
self.x = x
@property
def x(self) -> int:
return self._x
@x.setter
def x(self, z: int):
if z > 1:
self._x = z
else:
raise ValueError
c= Container(x=10)
print(c)
c= Container()
print(c)
output is:
Container(x=10)
Container(x=30)
As far as I can see, this happens because actual __init__() generated
by the @dataclass decorator looks like:
def __init__(self, x:int = <property object at 0x106655db0>):
self.x = x
I came up with a really convoluted way to work around it (just for
fun, as this clearly defies the idea of dataclasses as a way to
decrease boilerplate code):
from dataclasses import dataclass, field
def set_property():
Container.x = property(Container.get_x, Container.set_x)
return 30
@dataclass
class Container:
x: int = field(default_factory=set_property)
def get_x(self) -> int:
return self._x
def set_x(self, z: int):
if z > 1:
self._x = z
else:
raise ValueError
c= Container(x=10)
print(c)
c= Container()
print(c)
output is:
Container(x=10)
Container(x=30)
So, what I'm missing here? Is there some way to use field() or
decorators to make property just work the same as in non-decorated
class?
Best regards,
Ivan Ivanyuk
More information about the Python-list
mailing list