<div dir="ltr">I'm sorry, but a solution that requires __class__ assignment is way too fragile for my taste.<br></div><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Feb 5, 2018 at 6:28 AM, Nick Coghlan <span dir="ltr"><<a href="mailto:ncoghlan@gmail.com" target="_blank">ncoghlan@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">On 5 February 2018 at 15:49, Guido van Rossum <<a href="mailto:guido@python.org">guido@python.org</a>> wrote:<br>
> My point is that once you have one of those patterns in place, changing your<br>
> code to avoid them may be difficult. And yet your code may treat the objects<br>
> as essentially immutable after the initialization phase (e.g. a parse tree).<br>
> So if you create a dataclass and start coding like that for a while, and<br>
> much later you need to put one of these into a set or use it as a dict key,<br>
> switching to frozen=True may not be a quick option. And writing a __hash__<br>
> method by hand may feel like a lot of busywork. So this is where<br>
> [unsafe_]hash=True would come in handy.<br>
><br>
> I think naming the flag unsafe_hash should take away most objections, since<br>
> it will be clear that this is not a safe thing to do. People who don't<br>
> understand the danger are likely to copy a worse solution from StackOverflow<br>
> anyway. The docs can point to frozen=True and explain the danger.<br>
<br>
</span>Aye, calling the flag unsafe_hash would convert me from -1 to -0.<br>
<br>
The remaining -0 is because I think there's a different and more<br>
robust way to tackle your example use case:<br>
<br>
# Mutable initialization phase<br>
>>> from dataclasses import dataclass<br>
>>> @dataclass<br>
... class Example:<br>
... a: int<br>
... b: int<br>
...<br>
>>> c = Example(None, None)<br>
>>> c<br>
Example(a=None, b=None)<br>
>>> c.a = 1<br>
>>> c.b = 2<br>
>>> c<br>
Example(a=1, b=2)<br>
<br>
<br>
# Frozen usage phase<br>
>>> @dataclass(frozen=True)<br>
... class LockedExample(Example):<br>
... pass<br>
...<br>
>>> c.__class__ = LockedExample<br>
>>> c.a = 1<br>
<span class=""> Traceback (most recent call last):<br>
</span> File "<stdin>", line 1, in <module><br>
File "/home/ncoghlan/devel/cpython/<wbr>Lib/dataclasses.py", line 448,<br>
in _frozen_setattr<br>
raise FrozenInstanceError(f'cannot assign to field {name!r}')<br>
dataclasses.<wbr>FrozenInstanceError: cannot assign to field 'a'<br>
>>> c.b = 2<br>
<span class=""> Traceback (most recent call last):<br>
</span> File "<stdin>", line 1, in <module><br>
File "/home/ncoghlan/devel/cpython/<wbr>Lib/dataclasses.py", line 448,<br>
in _frozen_setattr<br>
raise FrozenInstanceError(f'cannot assign to field {name!r}')<br>
dataclasses.<wbr>FrozenInstanceError: cannot assign to field 'b'<br>
>>> hash(c)<br>
3713081631934410656<br>
<br>
The gist of that approach is to assume that there will be *somewhere*<br>
in the code where it's possible to declare the construction of the<br>
instance "complete", and flip the nominal class over to the frozen<br>
subclass to make further mutation unlikely, even though the true<br>
underlying type is still the mutable version.<br>
<br>
That said, if we do provide "unsafe_hash", then the documentation for<br>
that flag becomes a place where we can explicitly suggest using a<br>
frozen subclass instead.<br>
<div class="HOEnZb"><div class="h5"><br>
Cheers,<br>
Nick.<br>
<br>
--<br>
Nick Coghlan | <a href="mailto:ncoghlan@gmail.com">ncoghlan@gmail.com</a> | Brisbane, Australia<br>
</div></div></blockquote></div><br><br clear="all"><br>-- <br><div class="gmail_signature" data-smartmail="gmail_signature">--Guido van Rossum (<a href="http://python.org/~guido" target="_blank">python.org/~guido</a>)</div>
</div>