Single-dispatch generic function decorator. Transforms a function into a generic function, which can have different behaviours depending upon the type of its first argument. The decorated function acts as the default implementation, and additional implementations can be registered u
(func)
| 894 | return registry.get(match) |
| 895 | |
| 896 | def singledispatch(func): |
| 897 | """Single-dispatch generic function decorator. |
| 898 | |
| 899 | Transforms a function into a generic function, which can have different |
| 900 | behaviours depending upon the type of its first argument. The decorated |
| 901 | function acts as the default implementation, and additional |
| 902 | implementations can be registered using the register() attribute of the |
| 903 | generic function. |
| 904 | """ |
| 905 | # There are many programs that use functools without singledispatch, so we |
| 906 | # trade-off making singledispatch marginally slower for the benefit of |
| 907 | # making start-up of such applications slightly faster. |
| 908 | import weakref |
| 909 | |
| 910 | registry = {} |
| 911 | dispatch_cache = weakref.WeakKeyDictionary() |
| 912 | cache_token = None |
| 913 | |
| 914 | def dispatch(cls): |
| 915 | """generic_func.dispatch(cls) -> <function implementation> |
| 916 | |
| 917 | Runs the dispatch algorithm to return the best available implementation |
| 918 | for the given *cls* registered on *generic_func*. |
| 919 | |
| 920 | """ |
| 921 | nonlocal cache_token |
| 922 | if cache_token is not None: |
| 923 | current_token = get_cache_token() |
| 924 | if cache_token != current_token: |
| 925 | dispatch_cache.clear() |
| 926 | cache_token = current_token |
| 927 | try: |
| 928 | impl = dispatch_cache[cls] |
| 929 | except KeyError: |
| 930 | try: |
| 931 | impl = registry[cls] |
| 932 | except KeyError: |
| 933 | impl = _find_impl(cls, registry) |
| 934 | dispatch_cache[cls] = impl |
| 935 | return impl |
| 936 | |
| 937 | def _is_valid_dispatch_type(cls): |
| 938 | if isinstance(cls, type): |
| 939 | return True |
| 940 | return (isinstance(cls, UnionType) and |
| 941 | all(isinstance(arg, type) for arg in cls.__args__)) |
| 942 | |
| 943 | def register(cls, func=None): |
| 944 | """generic_func.register(cls, func) -> func |
| 945 | |
| 946 | Registers a new implementation for the given *cls* on a *generic_func*. |
| 947 | |
| 948 | """ |
| 949 | nonlocal cache_token |
| 950 | if _is_valid_dispatch_type(cls): |
| 951 | if func is None: |
| 952 | return lambda f: register(cls, f) |
| 953 | else: |
no test coverage detected
searching dependent graphs…