-
-
Notifications
You must be signed in to change notification settings - Fork 32.1k
dataclass overriding a property in the parent class is broken #121354
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Good catch, thank you! I will take a look. |
I reproduced the same behaviour without class A1:
def __init__(self, a):
self.a = a
@property
def b(self) -> int:
return 1
class B1(A1):
def __init__(self, a, b=0) -> None:
self.a = a
self.b = b
print(B1.b)
print(B1(1).b) produces:
So, I think that there's no actual bug. When For your case you can do: @dc.dataclass
class B(A):
_x: int | None = None
@property
def b(self) -> int:
return self._x or 0
@b.setter
def b(self, value: int) -> None:
self._x = value |
Oh, |
Line 1027 in db39bc4
I think that what can be done for this case: we can check that if a field overrides a property, then we can delete that property from our class namespace. This way both |
Or we can leave this as-is, because:
cc @ericvsmith |
@sobolevn Yes, your original example is WAI - since property wasn't overriden. But here we explicity create a new override, so naively i would expect it to override the property definition. E.g. i can override property with another property or another class variable. Would it make sense for dataclass to just always create a class attribute? class B(a):
b: int = dc.field(...) should have B.b == dc.field, because this is what I would expect from such an assignment. THis way you don't need to do any special handling of properties. Line 1025 in db39bc4
There is a comment in dataclass saying that if defautl_factory is specified "it should not be set at all in the post-processsed class", but it is not clear "why". if f.default is MISSING:
# If there's no default, delete the class attribute.
# This happens if we specify field(repr=False), for
# example (that is, we specified a field object, but
# no default value). Also if we're using a default
# factory. The class attribute should not be set at
# all in the post-processed class.
delattr(cls, f.name) |
The example above of the workaround, isn't really very useful: @dc.dataclass
class B(A):
_x: int | None = None
@property
def b(self) -> int:
return self._x or 0
@b.setter
def b(self, value: int) -> None:
self._x = value This is not a good solution at all, since i won't be able to pass b=3 in the constructor, and so will need to expose user to the implementation details of the class. Currently we just switched to use |
I think the argument for not setting the class attribute is that My inclination would be to leave things as-is. |
But we do set attribute in some cases (e.g. when default is set) just not
the others (when default_facotry). Which is confusing to say the least.
…On Thu, Sep 26, 2024 at 12:01 PM Eric V. Smith ***@***.***> wrote:
I think the argument for not setting the class attribute is that field is
supposed to be invisible to the class user.
My inclination would be to leave things as-is.
—
Reply to this email directly, view it on GitHub
<#121354 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ABVIDWCXJNKWOH4D57QU5CTZYRK2DAVCNFSM6AAAAABKKOB2VGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDGNZXG4YTMNJZGU>
.
You are receiving this because you authored the thread.Message ID:
***@***.***>
|
The argument there is that the default values would be useful, but not the default non-values (that is, |
Hello, I was about to open an issue because I came across this in quite a different context, while realizing >>> desc = lambda: ... # Random non-data descriptor
>>>
>>> class A:
... x: ... = desc
...
>>> A().x
<bound method <lambda> of <__main__.A object at 0x10bea96d0>>
>>>
>>> @dataclass
... class B:
... x: ... = desc
...
>>> B().x
<function <lambda> at 0x10bcf9f80> Notice how the return value is "bound" in the vanilla case, and not bound in the >>> vars(A())
{}
>>> vars(B())
{'x': <function <lambda> at 0x10bcf9f80>} The problem now is that for data-descriptors like >>> @dataclass
... class C:
... x: ... = property(lambda _: ...)
...
>>> C()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 3, in __init__
AttributeError: property 'x' of 'C' object has no setter To keep consistent behaviour with the look-up that shortcuts I think this may require a bit of rethinking for |
Uh oh!
There was an error while loading. Please reload this page.
Bug report
Bug description:
Consider the following snippet
Dataclass apparently doesn't create a class attribute, so class B ends up with
property
,b
of class A, which seems surprising, especially given that there is explicit assignent of field b in class B(A).So this results in:
If i replace definition of
b
like sob: int = dc.field(default=0)
, or withb: int = 0
then everything works as expected:I think it would be nice if dataclass would always create a class attribute (especially if there is explicit assignment!)
so that overloads work as expected.
CPython versions tested on:
3.11, 3.12
Operating systems tested on:
Linux
The text was updated successfully, but these errors were encountered: