-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Use match statement in checkers (5) #10544
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
return isinstance(node, nodes.Const) and isinstance(node.value, int) | ||
match node: | ||
case nodes.Const(value=int()): | ||
return True | ||
return False |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not entirely sure about these. I do find the match-case variant much more readable but the indentation and dedicated return True
and return False
are worse.
Maybe Python also needs a match expression which could be used in return statements. (Similarly to if expressions). Something like
return (node match nodes.Const(value=int()))
ed2fb5c
to
1e8198f
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #10544 +/- ##
==========================================
- Coverage 95.90% 95.89% -0.01%
==========================================
Files 177 177
Lines 19376 19410 +34
==========================================
+ Hits 18582 18613 +31
- Misses 794 797 +3
🚀 New features to boost your workflow:
|
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think all the one liner return should be reverted, I would keep only the one where the number of line with match is smaller or equivalent than before.
return node.expr.name in {"numpy", "nmp", "np"} | ||
match node: | ||
case nodes.Attribute(attrname="NaN", expr=nodes.Name(name=name)): | ||
return name in {"numpy", "nmp", "np"} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unrelated but I never saw nmp
in the wild. Completely died off in favor of np
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah. Haven't seen it either. Let's remove it.
Will do it with the other match followups.
return isinstance(func, nodes.FunctionDef) and ( | ||
func.type == "classmethod" or func.name == "__class_getitem__" | ||
) | ||
match func: | ||
case nodes.FunctionDef(type="classmethod") | nodes.FunctionDef( | ||
name="__class_getitem__" | ||
): | ||
return True | ||
return False |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perf probably worse (two checks for isinstance(FunctionDef)?), take twice as much space, feel forced, me no like.
if isinstance(node_a, nodes.Name) and isinstance(node_b, nodes.Name): | ||
return node_a.name == node_b.name # type: ignore[no-any-return] | ||
if isinstance(node_a, nodes.AssignName) and isinstance( | ||
node_b, nodes.AssignName | ||
): | ||
return node_a.name == node_b.name # type: ignore[no-any-return] | ||
if isinstance(node_a, nodes.Const) and isinstance(node_b, nodes.Const): | ||
return node_a.value == node_b.value # type: ignore[no-any-return] | ||
match (node_a, node_b): | ||
case ( | ||
[nodes.Name(name=a), nodes.Name(name=b)] | ||
| [nodes.AssignName(name=a), nodes.AssignName(name=b)] | ||
| [nodes.Const(value=a), nodes.Const(value=b)] | ||
): | ||
return a == b # type: ignore[no-any-return] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
Reverted most of these. Let me know if I've missed one.
Performance is indeed an interesting topic. Took some time to look into it some more. Although the match statement is pretty close for "normal" if-else statements, especially the class matcher seems to be a bit worse than Overall I've seen a ~3% performance impact (7:20 -> 7:35 for Home Assistant) from the recent match statement changes. That's not nothing but I think the readability improvements outweigh it. |
🤖 According to the primer, this change has no effect on the checked open source code. 🤖🎉 This comment was generated for commit cfec7c9 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you everything make sense now.
Regarding performance, I was thinking of the particular case where we remove a isinstance(func, nodes.FunctionDef) and (x or y)
by match func: case nodes.FunctionDef(x) | nodes.FunctionDef(y):
but I'm sad to learn that pylint is 3% slower because of the match changes.
I have to admit that the match statement is a bit of a black box which combines several checks in a meta language. So it's not directly obvious what's happing here. E.g. I thought the I spend some more time looking at it but this time even going as far as checking the eval loop in CPython directly. What I found are a couple of interesting facts
What does that mean for pylint? Yes, the match statement isn't the fastest especially the class pattern. Small speedups should be archivable if
Lastly, we should probably add a checker to make the CPython check for duplicate attributes in a class pattern redundant. |
Opened an issue for CPython with more details: python/cpython#138912 |
No description provided.