Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Can dataclass ordering avoid tuple wrappers for single field comparisons? #144191

Open
Assignees
ericvsmith
Labels
stdlibStandard Library Python modules in the Lib/ directorytopic-dataclassestype-featureA feature request or enhancement
@rhettinger

Description

@rhettinger

Proposal and Rationale

Whenorder=True, the generated rich comparison methods wrap the target field in a tuple. This makes sense when multiple fields are being compared. However for a single field, it adds unnecessary extra work: two extra tuple allocations and deallocations, a tuple compare, and superfluous equality check on the field.

For example, theheapq docs suggest making the following class:

fromdataclassesimportdataclass,fieldfromtypingimportAny@dataclass(order=True)classPrioritizedItem:priority:intitem:Any=field(compare=False)

The generated code for less-than operation is:

def__lt__(self,other):ifother.__class__isself.__class__:return (self.priority,)<(other.priority,)returnNotImplemented

Instead, it would be nicer to generate:

def__lt__(self,other):ifother.__class__isself.__class__:returnself.priority<other.priorityreturnNotImplemented

Behavior change

When the tuple wrapper was removed from__eq__ in favor of individual field comparisons linked byand, it resulted in faster code that matched what people would write by hand. However, it also caused issues where users had been relying on the identity checks inside the tuple comparison. That affects us here as well:

frommathimportnan>>>nan<=nanFalse>>> (nan,)<= (nan,)True

Unlike the impact of the__eq__ change, users of ordering operations are far less likely to be relying on identity-implies-equality.

One reason is that__eq__ is used with hashing but ordering operations are not. So the prior change affecteddict() andset() while the proposed change does not.

Another reason is that it only affects__le__ and__ge__ but not__eq__,__ne__,__lt__, and__ge__, so it doesn't show-up 100% of the time.

Also Python's ordering tools (sorted,min,max,nsmallest,nlargest,merge,bisect, andheapq) do not use__le__ and__ge__. So they are entirely unaffected.

The upside of the behavior change is that it fixes an existing inconsistency between '<', '==', and '<=':

>>>PrioritizedItem(nan,'x')<PrioritizedItem(nan,'y')False>>>PrioritizedItem(nan,'x')==PrioritizedItem(nan,'y')False# Inconsistent with the previous two calls>>>PrioritizedItem(nan,'x')<=PrioritizedItem(nan,'y')True

This inconsistency is unexpected because it does not show up in hand-written code:

>>>nan<nanFalse>>>nan==nanFalse>>>nan<=nanFalse

Linked PRs

Metadata

Metadata

Assignees

Labels

stdlibStandard Library Python modules in the Lib/ directorytopic-dataclassestype-featureA feature request or enhancement

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions


    [8]ページ先頭

    ©2009-2026 Movatter.jp