On 5 February 2018 at 15:49, Guido van Rossum <gu...@python.org> wrote:
> My point is that once you have one of those patterns in place, changing your
> code to avoid them may be difficult. And yet your code may treat the objects
> as essentially immutable after the initialization phase (e.g. a parse tree).
> So if you create a dataclass and start coding like that for a while, and
> much later you need to put one of these into a set or use it as a dict key,
> switching to frozen=True may not be a quick option. And writing a __hash__
> method by hand may feel like a lot of busywork. So this is where
> [unsafe_]hash=True would come in handy.
>
> I think naming the flag unsafe_hash should take away most objections, since
> it will be clear that this is not a safe thing to do. People who don't
> understand the danger are likely to copy a worse solution from StackOverflow
> anyway. The docs can point to frozen=True and explain the danger.

Aye, calling the flag unsafe_hash would convert me from -1 to -0.

The remaining -0 is because I think there's a different and more
robust way to tackle your example use case:

    # Mutable initialization phase
    >>> from dataclasses import dataclass
    >>> @dataclass
    ... class Example:
    ...     a: int
    ...     b: int
    ...
    >>> c = Example(None, None)
    >>> c
    Example(a=None, b=None)
    >>> c.a = 1
    >>> c.b = 2
    >>> c
    Example(a=1, b=2)


    # Frozen usage phase
    >>> @dataclass(frozen=True)
    ... class LockedExample(Example):
    ...     pass
    ...
    >>> c.__class__ = LockedExample
    >>> c.a = 1
    Traceback (most recent call last):
     File "<stdin>", line 1, in <module>
     File "/home/ncoghlan/devel/cpython/Lib/dataclasses.py", line 448,
in _frozen_setattr
       raise FrozenInstanceError(f'cannot assign to field {name!r}')
    dataclasses.FrozenInstanceError: cannot assign to field 'a'
    >>> c.b = 2
    Traceback (most recent call last):
     File "<stdin>", line 1, in <module>
     File "/home/ncoghlan/devel/cpython/Lib/dataclasses.py", line 448,
in _frozen_setattr
       raise FrozenInstanceError(f'cannot assign to field {name!r}')
    dataclasses.FrozenInstanceError: cannot assign to field 'b'
    >>> hash(c)
    3713081631934410656

The gist of that approach is to assume that there will be *somewhere*
in the code where it's possible to declare the construction of the
instance "complete", and flip the nominal class over to the frozen
subclass to make further mutation unlikely, even though the true
underlying type is still the mutable version.

That said, if we do provide "unsafe_hash", then the documentation for
that flag becomes a place where we can explicitly suggest using a
frozen subclass instead.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncogh...@gmail.com   |   Brisbane, Australia
_______________________________________________
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com

Reply via email to