A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://mail.python.org/pipermail/python-dev/2018-February/152303.html below:

[Python-Dev] Should the dataclass frozen property apply to subclasses?

[Python-Dev] Should the dataclass frozen property apply to subclasses?Eric V. Smith eric at trueblade.com
Mon Feb 26 13:35:11 EST 2018
On 2/22/18 9:43 PM, Nick Coghlan wrote:
> On 22 February 2018 at 20:55, Eric V. Smith <eric at trueblade.com> wrote:
>> On 2/22/2018 1:56 AM, Raymond Hettinger wrote:
>>> When working on the docs for dataclasses, something unexpected came up.
>>> If a dataclass is specified to be frozen, that characteristic is inherited
>>> by subclasses which prevents them from assigning additional attributes:
>>>
>>>       >>> @dataclass(frozen=True)
>>>       class D:
>>>               x: int = 10
>>>
>>>       >>> class S(D):
>>>               pass
>>>
>>>       >>> s = S()
>>>       >>> s.cached = True
>>>       Traceback (most recent call last):
>>>         File "<pyshell#49>", line 1, in <module>
>>>           s.cached = True
>>>         File
>>> "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/dataclasses.py",
>>> line 448, in _frozen_setattr
>>>           raise FrozenInstanceError(f'cannot assign to field {name!r}')
>>>       dataclasses.FrozenInstanceError: cannot assign to field 'cached'
>>
>> This is because "frozen-ness" is implemented by adding __setattr__ and
>> __delattr__ methods in D, which get inherited by S.
>>
>>> Other immutable classes in Python don't behave the same way:
>>>
>>>
>>>       >>> class T(tuple):
>>>               pass
>>>
>>>       >>> t = T([10, 20, 30])
>>>       >>> t.cached = True
>>>
>>>       >>> class F(frozenset):
>>>               pass
>>>
>>>       >>> f = F([10, 20, 30])
>>>       >>> f.cached = True
>>>
>>>       >>> class B(bytes):
>>>               pass
>>>
>>>       >>> b = B()
>>>       >>> b.cached = True
>>
>> The only way I can think of emulating this is checking in __setattr__ to see
>> if the field name is a field of the frozen class, and only raising an error
>> in that case.
> If you were going to do that then it would likely make more sense to
> convert the frozen fields to data descriptors, so __setattr__ only
> gets called for attempts to add new attributes.
>
> Then for the `frozen=False` case, the decorator could force
> __setattr__ and __delattr__ back to the default implementations from
> object, rather than relying on the behaviour inherited from base
> classes.

I guess it depends on what we're trying to do. By using data 
descriptors, we'd be saying "the fields can't be modified, but other 
parts of the class can". For example, what should happen here:

@dataclass(frozen=True)
class F:
    i: int

f = F(10)
f.i = 0   # should be an error
f.j = 0   # should this be an error? It's not a field.

I was hoping to get all of this finished today, by a2, but it looks like 
that's not going to happen.
>> A related issue is that dataclasses derived from frozen dataclasses are
>> automatically "promoted" to being frozen.
>>
>>>>> @dataclass(frozen=True)
>> ... class A:
>> ...     i: int
>> ...
>>>>> @dataclass
>> ... class B(A):
>> ...     j: int
>> ...
>>>>> b = B(1, 2)
>>>>> b.j = 3
>> Traceback (most recent call last):
>>    File "<stdin>", line 1, in <module>
>>    File "C:\home\eric\local\python\cpython\lib\dataclasses.py", line 452, in
>> _frozen_setattr
>>      raise FrozenInstanceError(f'cannot assign to field {name!r}')
>> dataclasses.FrozenInstanceError: cannot assign to field 'j'
>>
>> Maybe it should be an error to declare B as non-frozen?
> It would be nice to avoid that, as a mutable subclass of a frozen base
> class could be a nice way to model hashable-but-mutable types:
>
>      >>> @dataclass(frozen=True) # This is the immutable/hashable bit
>      ... class A:
>      ...     i: int
>      ...
>      >>> @dataclass # This adds the mutable-but-comparable parts
>      ... class B(A):
>      ...     j: int
>      ...     __hash__ = A.__hash__
>
>
> However, disallowing this case for now *would* be a reasonable way to
> postpone making a decision until 3.8 - in the meantime, folks would
> still be able to experiment by overriding __setattr__ and __delattr__
> after the dataclass decorator sets them.
>

For today, I'm going to make it an error to derive a frozen dataclass 
from a non-frozen dataclass, and also an error to derive a non-frozen 
dataclass from a frozen dataclass. With any luck (and Guido and Ned 
willing), we can address this by a3.

Eric

More information about the Python-Dev mailing list

RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4