Eric V. Smith <e...@trueblade.com> added the comment: Here is my proposal for making it easier for the user to supply dunder methods that dataclasses would otherwise automatically add to the class.
For all of these cases, when I talk about init=, repr=, eq=, order=, hash=, or frozen=, I'm referring to the parameters to the dataclass decorator. When checking if a dunder method already exists, I mean check for an entry in the class's __dict__. I never check to see if a member is defined in a base class. Let's get the easy ones out of the way first. __init__ If __init__ exists or init=False, don't generate __init__. __repr__ If __repr__ exists or repr=False, don't generate __repr__. __setattr__ __delattr__ If frozen=True and either of these methods exist, raise a TypeError. These methods are needed for the "frozen-ness" of the class to be implemented, and if they're already set then that behavior can't be enforced. __eq__ If __eq__ exists or eq=False, don't generate __eq__. And now the harder ones: __ne__ I propose to never generate a __ne__ method. Python will call __eq__ and negate the result for you. If you feel you really need a non-matching __ne__, then you can write it yourself without interference from dataclasses. __lt__ __le__ __gt__ __ge__ I propose to treat each of these individually, but for each of them using the value of the order= parameter. So: If __lt__ exists or order=False, don't generate __lt__. If __le__ exists or order=False, don't generate __le__. If __gt__ exists or order=False, don't generate __gt__. If __ge__ exists or order=False, don't generate __ge__. If for some crazy reason you want to define some of these but not others, then set order=False and write your desired methods. __hash__ Whether dataclasses might generate __hash__ depends on the values of hash=, eq=, and frozen=. Note that the default value of hash= is None. See below for an explanation. If hash=False, never generate __hash__. If hash=True, generate __hash__ unless it already exists. If hash=None (the default), then use this table to decide whether and how to generate __hash__: eq=? frozen=? __hash__ False False do not generate __hash__ False True do not generate __hash__ True False set __hash__ to None unless it already exists True True generate __hash__ unless it already exists and is None Note that it's almost always a bad idea to specify hash=True or hash=False. The action based on the above table (where hash=None, the default), is usually the correct behavior. One special case to recognize is if the class defines a __eq__. In this case, Python will assign __hash__=None before the dataclass decorator is called. The decorator cannot distinguish between these two cases (except possibly by using the order of __dict__ keys, but that seems overly fragile): @dataclass class A: def __eq__(self, other): pass @dataclass class B: def __eq__(self, other): pass __hash__ = None This is the source of the last line in the above table: for a dataclass where eq=True, frozen=True, and hash=None, if __hash__ is None it will still be overwritten. The assumption is that this is what the user wants, but it's a tricky corner case. It also occurs if setting hash=True and defining __eq__. Again, it's not expected to come up in normal usage. ---------- keywords: -patch _______________________________________ Python tracker <rep...@bugs.python.org> <https://bugs.python.org/issue32513> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com