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 registe
(func)
| 798 | return registry.get(match) |
| 799 | |
| 800 | def singledispatch(func): |
| 801 | """Single-dispatch generic function decorator. |
| 802 | |
| 803 | Transforms a function into a generic function, which can have different |
| 804 | behaviours depending upon the type of its first argument. The decorated |
| 805 | function acts as the default implementation, and additional |
| 806 | implementations can be registered using the register() attribute of the |
| 807 | generic function. |
| 808 | """ |
| 809 | # There are many programs that use functools without singledispatch, so we |
| 810 | # trade-off making singledispatch marginally slower for the benefit of |
| 811 | # making start-up of such applications slightly faster. |
| 812 | import types, weakref |
| 813 | |
| 814 | registry = {} |
| 815 | dispatch_cache = weakref.WeakKeyDictionary() |
| 816 | cache_token = None |
| 817 | |
| 818 | def dispatch(cls): |
| 819 | """generic_func.dispatch(cls) -> <function implementation> |
| 820 | |
| 821 | Runs the dispatch algorithm to return the best available implementation |
| 822 | for the given *cls* registered on *generic_func*. |
| 823 | |
| 824 | """ |
| 825 | nonlocal cache_token |
| 826 | if cache_token is not None: |
| 827 | current_token = get_cache_token() |
| 828 | if cache_token != current_token: |
| 829 | dispatch_cache.clear() |
| 830 | cache_token = current_token |
| 831 | try: |
| 832 | impl = dispatch_cache[cls] |
| 833 | except KeyError: |
| 834 | try: |
| 835 | impl = registry[cls] |
| 836 | except KeyError: |
| 837 | impl = _find_impl(cls, registry) |
| 838 | dispatch_cache[cls] = impl |
| 839 | return impl |
| 840 | |
| 841 | def _is_union_type(cls): |
| 842 | from typing import get_origin, Union |
| 843 | return get_origin(cls) in {Union, types.UnionType} |
| 844 | |
| 845 | def _is_valid_dispatch_type(cls): |
| 846 | if isinstance(cls, type): |
| 847 | return True |
| 848 | from typing import get_args |
| 849 | return (_is_union_type(cls) and |
| 850 | all(isinstance(arg, type) for arg in get_args(cls))) |
| 851 | |
| 852 | def register(cls, func=None): |
| 853 | """generic_func.register(cls, func) -> func |
| 854 | |
| 855 | Registers a new implementation for the given *cls* on a *generic_func*. |
| 856 | |
| 857 | """ |
no test coverage detected