Repository navigation
Performance of typing._ProtocolMeta._get_protocol_attrs and isinstance #74690
Description
Activity
orenbenkiki commented
on May 29, 2017 orenbenkikimannequinMannequinAuthorMore actionsIn 3.6.0, invocation of isinstance calls typing._ProtocolMeta._get_protocol_attrs.
This creates a set of all attributes in all base classes, loops on these attributes to check they exist, and discards the set. It is very slow.My program uses isinstance to allow for flexibility in parameter types in certain key functions. I realize that using isinstance is frowned upon, but it seems to make sense in my case.
As a result, >95% of its run-time is inside typing._ProtocolMeta._get_protocol_attrs (!).
I have created a simple wrapper around isinstance which caches its result with a Dict[Tuple[type, type], bool]. This solved the performance problem, but introduced a different problem - type checking.
I use mypy and type annotations, and my code cleanly type-checks (with the occasional # type: ignore). If I switch to using my own isinstance function, then mypy's type inference no longer treats it as special, so it starts complaining about all uses of values protected by if isinstance(value, SomeType): ...
I propose that either the private typing._ProtocolMeta.__subclasscheck__ (which invokes _get_protocol_attrs), or the public isinstance, would be modified to cache their results.
I can create a PR for either approach, if this is acceptable.
- addedstdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directoryperformancePerformance or resource usagePerformance or resource usage
on May 29, 2017 Thanks for reporting!
The runtime implementation of protocol classes will be thoroughly reworked as a part of PEP-544, see also python/typing#417 for a proof of concept runtime implementation.
Also, there is another ongoing discussion python/typing#432 about a global refactoring of typing module that will significantly improve performance.
Therefore, I would wait with any large PRs until these two stories are settled. If you still want to propose a small PR, you can do this at the upstream typing repo https://github.com/python/typing
@orenbenkiki @ilevkivskyi What is the status of this issue, five years on?
TBH I am not sure this issue is still relevant (at least I didn't hear any recent complaints about
Protocolperformance). @orenbenkiki is performance still bad for your application?Hm, actually the short-circuiting proposed in that comment may be a good idea (unless I forgot something) for a simple perf optimization (btw FWIW this is what mypy does internally, it always checks nominal subtypig first).
Reacted by Alex Waygood@posita appears to have implemented optimised versions of
ProtocolMetahere and here.(I haven't studied the code for either link, but may be worth looking at!)
For color, the current implementation lives in Beartype and is divided among two classes:
The meat is in
_CachingProtocolMetawhereas theProtocolis basically a hack to work around some standard library implementation details and could likely be eliminated. At a high level,_CachingProtocolMetaoverrides__instancecheck__to perform an examination of whether an object "satisfies" a Protocol definition similar totyping._ProtocolMeta.__instancecheck__and then caches the result by that object's type. Note the asymmetry: the examination is performed on the object, but it is assumed that all objects of the first-examined object's type are consistent. This makes the implementation ill-suited for runtime-composed "types" or monkey-patched objects.Happy to discuss further, if desired.
Caching may need a more careful consideration (especially w.r.t. monkey-patching classes). I was specifically referring to this idea
class _ProtocolMeta(ABCMeta): # … def __instancecheck__(cls, instance): if super().__instancecheck__(instance): # Short circuit for direct inheritors return True else: # … existing implementation that checks method names, etc. … return False
@posita Do you have any good code base where you can benchmark this w.r.t. current implementation?
I can probably do something crude with
numerary's anddyce's respective batteries of unit tests. Those are what motivatedbeartype.typing._typingpep544._CachingProtocolMetain the first place. Give me a few days and I can probably throw something together.Reacted by Alex Waygood43 remaining items
- added a commit that references this issue
on May 18, 2023 - added a commit that references this issue
on May 21, 2023 - added a commit that references this issue
on Jun 1, 2023 - added a commit that references this issue
on Jun 2, 2023 - added a commit that references this issue
on Jun 2, 2023 - added a commit that references this issue
on Jun 3, 2023 - added 4 commits that reference this issue
on Dec 4, 2023
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
Linked PRs
_get_protocol_attrstwice in_ProtocolMeta.__instancecheck__#103141typing._get_protocol_attrs#103152_ProtocolMeta.__instancecheck__#103159_get_protocol_attrsand_callable_members_onlyat protocol class creation time, not duringisinstance()checks #103160typing._ProtocolMeta.__instancecheck__#103280typing._ProtocolMeta.__instancecheck__: Exit early for protocols that only have callable members #103310isinstance()andissubclass()calls against runtime-checkable protocols by avoiding costlysuper()calls #112708_ProtocolMeta.__subclasscheck__#112717