I was reading a blog explaining dataclasses and was confused about its description of the unsafe_hash parameter.
Reading the docs was also confusing so I decided to write a program that generated a truth table of all the parameters said to govern __hash__ generation for dataclasses and check the output generated in each case.
The code
# -*- coding: utf-8 -*-
"""
__hash__ generation for @dataclass()
Documentation could be better w.r.t. unsafe_hash:
https://docs.python.org/3/library/dataclasses.html?highlight=unsafe_hash
Parameters:
eq: default True, equality checks as a tuple of values.
frozen: default False, stops field re-assignment.
unsafe_hash default False, Forces the gen of a __hash__ method
irrespective of eq and frozen values.
__hash__ methods on a dataclass:
Ref: https://docs.python.org/3/reference/datamodel.html#object.__hash__
If set to None: class is unhashable.
If present: class is hashable
If absent: class is unhashable; eq *should* be false too.
Created on Sun Oct 11 10:12:17 2020
@author: Paddy3118
"""
from dataclasses import dataclass
from itertools import product
print(__doc__ + """
TABLE: generated by testing the generated dadaclass
unsafe_hash, eq, frozen => Dataclass __hash__ state""")
for unsafe_hash, eq, frozen in product((False, True), repeat=3):
@dataclass(eq=eq, frozen=frozen, unsafe_hash=unsafe_hash)
class Dc:
x: int
if '__hash__' not in dict(Dc.__dict__):
state = 'ABSENT'
elif dict(Dc.__dict__)['__hash__'] is None:
state = 'SET_NONE (Unhashable)'
else:
state = 'PRESENT'
print(f"{unsafe_hash!s:5}, {eq!s:5}, {frozen!s:5} => {state}")
del Dc
The output:
# -*- coding: utf-8 -*- """ __hash__ generation for @dataclass() Documentation could be better w.r.t. unsafe_hash: https://docs.python.org/3/library/dataclasses.html?highlight=unsafe_hash Parameters: eq: default True, equality checks as a tuple of values. frozen: default False, stops field re-assignment. unsafe_hash default False, Forces the gen of a __hash__ method irrespective of eq and frozen values. __hash__ methods on a dataclass: Ref: https://docs.python.org/3/reference/datamodel.html#object.__hash__ If set to None: class is unhashable. If present: class is hashable If absent: class is unhashable; eq *should* be false too. Created on Sun Oct 11 10:12:17 2020 @author: Paddy3118 """ from dataclasses import dataclass from itertools import product print(__doc__ + """ TABLE: generated by testing the generated dadaclass unsafe_hash, eq, frozen => Dataclass __hash__ state""") for unsafe_hash, eq, frozen in product((False, True), repeat=3): @dataclass(eq=eq, frozen=frozen, unsafe_hash=unsafe_hash) class Dc: x: int if '__hash__' not in dict(Dc.__dict__): state = 'ABSENT' elif dict(Dc.__dict__)['__hash__'] is None: state = 'SET_NONE (Unhashable)' else: state = 'PRESENT' print(f"{unsafe_hash!s:5}, {eq!s:5}, {frozen!s:5} => {state}") del Dc
__hash__ generation for @dataclass() Documentation could be better w.r.t. unsafe_hash: https://docs.python.org/3/library/dataclasses.html?highlight=unsafe_hash Parameters: eq: default True, equality checks as a tuple of values. frozen: default False, stops field re-assignment. unsafe_hash default False, Forces the gen of a __hash__ method irrespective of eq and frozen values. __hash__ methods on a dataclass: Ref: https://docs.python.org/3/reference/datamodel.html#object.__hash__ If set to None: class is unhashable. If present: class is hashable If absent: class is unhashable; eq *should* be false too. Created on Sun Oct 11 10:12:17 2020 @author: Paddy3118 TABLE: generated by testing the generated dadaclass unsafe_hash, eq, frozen => Dataclass __hash__ state False, False, False => ABSENT False, False, True => ABSENT False, True , False => SET_NONE (Unhashable) False, True , True => PRESENT True , False, False => PRESENT True , False, True => PRESENT True , True , False => PRESENT True , True , True => PRESENT
Conclusion:
Set eq and frozen as appropriate and the __hash__ method is likely to be what you want. Only set unsafe_hash if you know what you are doing.
End.
No comments:
Post a Comment