Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python 3.7: dataclass does not raise `TypeError` for `eq=False`

I was trying out the new dataclasses in Python 3.7

The dataclass decorator can be passed arguments to control the dunder functions that are added to the class.

For some reason, the decorator does not seem to raise TypeError for eq=False argument.

As per the docs:

eq: If true (the default), an __eq__ method will be generated. 
This method compares the class as if it were a tuple of its fields, in order. 
Both instances in the comparison must be of the identical type

If I understand correctly, if i pass eq = False, __eq__ function will not be added, and a TypeError should be thrown when comparing two instances of the same class. Instead, the eq parameter seems to have no effect.

@dataclass(eq = False)
class Number:
    val: int

a = Number(1)
b = Number(2)
c = Number(1)

a == b
False

a == c
False

The above does not raise TypeError and always evaluates to False.

@dataclass()
class Number:
    val: int

a = Number(1)
b = Number(2)
c = Number(1)

a
Number(val = 1)

a == b
False

a == c
True

The other arguments(eg: order, repr) seem to behave as expected

@dataclass(order = False, repr = False)
class Number:
    val:int

a = Number(1)
b = Number(2)
c = Number(1)

a
<__main__.Number object at 0x7fe1036c8b38>

a < b
Traceback (most recent call last):                                                                                                          
  File "<stdin>", line 1, in <module>                                                                                                       
TypeError: '<' not supported between instances of 'Number' and 'Number' 

Is there some gap in my understanding?

I am using docker image python/rc-stretch

like image 982
xssChauhan Avatar asked Jun 29 '18 13:06

xssChauhan


2 Answers

In python3.7, given the following dataclass definition

@dataclass(eq=False)
class Number:
    val: int

the expected result for Number(1) == Number(1) is False. This is correct since setting eq = True only overrides the default python-object equality function, which just checks for identical references (same as Number(1) is Number(1), which might more obviously evaluate to false) in this case.


The dataclass specification is a bit lacking here. It explains the eq parameter with

eq: If true (the default), an __eq__ method will be generated. This method compares the class as if it were a tuple of its fields, in order. [...]

but in order to understand the issue you ran into, you also need to know that the basic python object already comes with an __eq__ function:

>>> class A: pass
...
>>> dir(A())
['__class__', '__delattr__', ... '__eq__', ...]  # has __eq__ already
like image 187
Arne Avatar answered Oct 20 '22 02:10

Arne


When you don't define __eq__, __eq__ will resolve to object.__eq__. That is what's happening when you create a dataclass with eq=False.

object.__eq__(self, other) is False unless self is other, i.e. unless the two are the same object.

like image 6
gerrit Avatar answered Oct 20 '22 02:10

gerrit