Another two micro-optimizations#19633
Conversation
| class FormalArgument: | ||
| def __init__(self, name: str | None, pos: int | None, typ: Type, required: bool) -> None: | ||
| self.name = name | ||
| self.pos = pos | ||
| self.typ = typ | ||
| self.required = required | ||
|
|
||
| def __eq__(self, other: object) -> bool: | ||
| if not isinstance(other, FormalArgument): | ||
| return NotImplemented | ||
| return ( | ||
| self.name == other.name | ||
| and self.pos == other.pos | ||
| and self.typ == other.typ | ||
| and self.required == other.required | ||
| ) | ||
|
|
||
| def __hash__(self) -> int: | ||
| return hash((self.name, self.pos, self.typ, self.required)) |
There was a problem hiding this comment.
Would a dataclass work here? According to the docs, the dataclass decorator is supported for native classes. https://mypyc.readthedocs.io/en/latest/native_classes.html#class-decorators
Not sure what the performance difference is though.
There was a problem hiding this comment.
It is true that dataclasses are extension, but looking at generated C, their constructor still uses **kwargs (i.e. involves creating a dictionary, which is slow). I didn't make measurements, but I guess dataclasses will be somewhere in between.
There was a problem hiding this comment.
Would slots=True work? There is also frozen which could be set to True as well.
There was a problem hiding this comment.
No, not that dictionary :-) The one to pack keyword arguments to constructor. Anyway, just to be sure, I tried that, and (as expected) neither changed the constructor calling logic (which is there I guess because constructor is auto-generated not by us).
This comment has been minimized.
This comment has been minimized.
Co-authored-by: Ali Hamdan <[email protected]>
This comment has been minimized.
This comment has been minimized.
|
Diff from mypy_primer, showing the effect of this PR on open source code: ibis (https://github.com/ibis-project/ibis)
- ibis/backends/sql/compilers/athena.py:16: error: Incompatible types in assignment (expression has type tuple[type[Median], type[RowID], ... <14 more items>], base class "TrinoCompiler" defined the type as tuple[type[Median], type[RowID], type[TimestampBucket], type[StringToTime]]) [assignment]
+ ibis/backends/sql/compilers/athena.py:16: error: Incompatible types in assignment (expression has type "tuple[type[Median], type[RowID], ... <14 more items>]", base class "TrinoCompiler" defined the type as "tuple[type[Median], type[RowID], type[TimestampBucket], type[StringToTime]]") [assignment]
apprise (https://github.com/caronc/apprise)
- apprise/cli.py:173: error: Incompatible types in assignment (expression has type tuple[str, str, ... <18 more items>], variable has type tuple[str, str, ... <21 more items>]) [assignment]
+ apprise/cli.py:173: error: Incompatible types in assignment (expression has type "tuple[str, str, ... <18 more items>]", variable has type "tuple[str, str, ... <21 more items>]") [assignment]
- apprise/plugins/signal_api.py:73: error: Incompatible types in assignment (expression has type tuple[str, str, ... <10 more items>], base class "URLBase" defined the type as tuple[()]) [assignment]
+ apprise/plugins/signal_api.py:73: error: Incompatible types in assignment (expression has type "tuple[str, str, ... <10 more items>]", base class "URLBase" defined the type as "tuple[()]") [assignment]
- apprise/plugins/notica.py:96: error: Incompatible types in assignment (expression has type tuple[str, str, ... <11 more items>], base class "URLBase" defined the type as tuple[()]) [assignment]
+ apprise/plugins/notica.py:96: error: Incompatible types in assignment (expression has type "tuple[str, str, ... <11 more items>]", base class "URLBase" defined the type as "tuple[()]") [assignment]
- apprise/plugins/enigma2.py:90: error: Incompatible types in assignment (expression has type tuple[str, str, ... <10 more items>], base class "URLBase" defined the type as tuple[()]) [assignment]
+ apprise/plugins/enigma2.py:90: error: Incompatible types in assignment (expression has type "tuple[str, str, ... <10 more items>]", base class "URLBase" defined the type as "tuple[()]") [assignment]
- apprise/plugins/email/base.py:95: error: Incompatible types in assignment (expression has type tuple[str, str, ... <10 more items>], base class "URLBase" defined the type as tuple[()]) [assignment]
+ apprise/plugins/email/base.py:95: error: Incompatible types in assignment (expression has type "tuple[str, str, ... <10 more items>]", base class "URLBase" defined the type as "tuple[()]") [assignment]
|
Here are two things:
FormalArgumenta native class. We create huge amount of these (as callable subtyping is one of the most common subtype checks), and named tuples creation is significantly slower than native classes.re.match()in a code path offormat_type(). This is relatively slow (as it is apy_call()) and it is called in almost every error message. This creates problems for code with many third-party dependencies where these errors are ignored anyway.FWIW in total these give ~0.5% together (I didn't measure individually, but I guess the most benefit for self-check is from the first one).