Python 3.7: класс данных не вызывает `TypeError` для` eq = False`

Я пробовал новый dataclasses в Python 3.7

Декоратору dataclass могут быть переданы аргументы для управления дополнительными функциями, которые добавляются к классу.

По какой-то причине декоратор, похоже, не вызывает TypeError для eq=False аргумента.

Согласно документам:

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

Если я правильно понимаю, если я пропущу eq = False, функция __eq__ не будет добавлена, и при сравнении двух экземпляров одного и того же класса должен появиться TypeError. Вместо этого параметр eq, похоже, не действует.

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

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

a == b
False

a == c
False

Вышеупомянутое не вызывает TypeError и всегда оценивается как 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

Другие аргументы (например: order, repr), похоже, ведут себя так, как ожидалось.

@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' 

Есть ли пробел в моем понимании?

Я использую образ докера python/rc-stretch


person xssChauhan    schedule 29.06.2018    source источник
comment
Вы пробовали @dataclass(eq = False, order = False) проверить первый случай?   -  person RedEyed    schedule 29.06.2018
comment
@RedEyed Только что попробовал. Еще смог сделать проверку на равенство. TypeError на ‹или›.   -  person xssChauhan    schedule 29.06.2018
comment
Невозможно воспроизвести на python3.7, поскольку после того, как я установил eq = False, любое сравнение с использованием == всегда возвращает False. Я проверю документ, соответствует ли это ожидаемому поведению.   -  person Arne    schedule 29.06.2018
comment
@Arne Вы правы. Мне нужно отредактировать вопрос.   -  person xssChauhan    schedule 29.06.2018


Ответы (2)


В python3.7, учитывая следующее определение класса данных

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

ожидаемый результат для Number(1) == Number(1) - False. Это правильно, поскольку настройка eq = True только переопределяет функцию проверки равенства объектов Python по умолчанию, который просто проверяет идентичные ссылки (то же самое, что и Number(1) is Number(1), который более очевидно может оцениваться как false) в этом случае.


Здесь немного не хватает спецификации класса данных. Он объясняет параметр eq с помощью

eq: если true (по умолчанию), будет сгенерирован метод __eq__. Этот метод сравнивает класс по порядку, как если бы он был кортежем его полей. [...]

но чтобы понять проблему, с которой вы столкнулись, вам также необходимо знать, что базовый объект python уже имеет функцию __eq__:

>>> class A: pass
...
>>> dir(A())
['__class__', '__delattr__', ... '__eq__', ...]  # has __eq__ already
person Arne    schedule 29.06.2018
comment
Можете ли вы прикрепить ссылку на ожидаемое выше поведение? - person xssChauhan; 29.06.2018
comment
См. Сравнение значений в документации: поведение по умолчанию для равенства сравнение (== и !=) основано на идентичности объектов. - person Patrick Haugh; 29.06.2018
comment
@PatrickHaugh Хорошая находка, искал что-то подобное, но не нашел =) - person Arne; 29.06.2018

Если вы не определите __eq__, __eq__ преобразуется в object.__eq__. Вот что происходит, когда вы создаете класс данных с eq=False.

object.__eq__(self, other) имеет значение False, если не self is other, т.е. если они не являются одним и тем же объектом.

person gerrit    schedule 29.06.2018