Metadata-Version: 1.1
Name: Dispatching
Version: 1.1.0
Summary: A library for overloading python functions
Home-page: https://github.com/Lucretiel/Dispatch
Author: Nathan West
Author-email: UNKNOWN
License: LGPLv3
Description: Dispatching
        ===========
        
        A python library for overloading functions on type and signature.
        
        Overview
        --------
        
        Sure, ``*args`` and ``**kwargs`` are great. But sometimes you need more-
        you need to have genuinely distinct behavior based on the types or
        layout of your arguments. ``dispatching`` allows you to do just that. By
        attaching type annotations to your functions, and decorating them with
        ``dispatch``, you can have a group of functions and automatically
        determine the correct one to call. No more ``elif isinstance`` chains,
        or ``len(args)``, or ``arg in kwargs``.
        
        Usage
        -----
        
        To use dispatching, create a ``DispatchGroup`` object. This object
        collects all the functions that should be tried when executing a
        dispatch call.
        
        .. code:: python
        
            import dispatching
            greetings = dispatching.DispatchGroup()
        
        To add a function to the dispatch group, decorate it with the
        ``dispatch`` member.
        
        .. code:: python
        
            @greetings.dispatch
            def greet(x: int):
                print("Hello, int!")
        
            @greetings.dispatch
            def greet(x: str):
                print("Hello, str!")
        
            greet(1)  # Prints "Hello, int!"
            greet('string')  # Prints "Hello, str!"
            greet([1, 2, 3])  # Raises DispatchError, a subclass of TypeError
        
        The argument annotation determines what function is called. Each
        function registered to the group is tried, in order, to have arguments
        bound to its parameter signature. The first one that matches is called.
        If none match, a DispatchError is raised.
        
        Not every argument needs to have an annotation. Use a completely
        unannotated function to create a base case, which will be called if
        nothing else matches:
        
        .. code:: python
        
            @greetings.dispatch
            def greet(x):
                print("Hello, mysterious stranger!")
        
            greet([1, 2, 3])  # Prints "Hello, mysterious stranger!"
            greet(1)  # Still prints "Hello, int!"
        
        Be careful, though. Functions are tried in the order that the are
        decorated, so adding additional overloads after a base case won't do any
        good:
        
        .. code:: python
        
            @greetings.dispatch
            def greet(x: list):
                print("Hello, list!")
        
            greet([1, 2, 3])  # still prints "Hello, mysterious stranger"
        
        To get around this, you can use the dispatch\_first decorator, which
        adds the function to the front of the list of functions to try:
        
        .. code:: python
        
            @greetings.dispatch_first
            def greet(x: list):
                print("Hello, list!")
        
            greet([1, 2, 3])  # now prints "Hello, list!"
        
        Other usage notes
        -----------------
        
        It is not nessesary to explicitly create a DispatchGroup object.
        Instead, you can use the global function ``dispatch`` to create a new
        ``DispatchGroup`` implicitly. The decorated functions will automatically
        have the ``dispatch`` and ``dispatch_first`` attributes attached to
        them, so that more overloads can be added.
        
        .. code:: python
        
            @dispatching.dispatch
            def half(x: int):
                return x / 2
        
            @half.dispatch
            def half(x: str):
                return x[0:len(x)/2]
        
        This applies when using an explicit ``DispatchGroup`` as well. Because
        everything has the attributes attached to it, it also isn't necessary to
        give all functions the same name, or to give them a different name than
        the ``DispatchGroup``.
        
        In addition to matching by type, you can match by number of arguments:
        
        .. code:: python
        
            @dispatching.dispatch
            def nargs(a):
                return 1
        
            @nargs.dispatch
            def nargs(a, b):
                return 2
        
            @nargs.dispatch
            def nargs(a, b, c):
                return 3
        
            assert nargs(1) == 1
            assert nargs(5, 4, 3) == 3
            assert nargs(2, 4) == 2
            #Using less than 1 or more than 3 will raise a DispatchError
        
        Or by predicate:
        
        .. code:: python
        
            def is_odd(x): return x % 2 == 1
            def is_even(x): return x % 2 == 0
        
            @dispatching.dispatch
            def evens_only(x: is_even):
                return x
        
            @evens_only.dispatch
            def evens_only(x: is_odd)
                raise ValueError(x)
        
        Or by value comparison:
        
        .. code:: python
        
            #Classic freshman recursion
        
            @dispatching.dispatch
            def fib(n: 0):
                return 1
        
            @fib.dispatch
            def fib(n: 1)
                return 1
        
            @fib.dispatch
            def fib(n):
                return fib(n-1) + fib(n-2)
        
        Examples
        --------
        
        Overload on number of arguments to make automatic decorators:
        
        .. code:: python
        
            from dispatching import dispatch
        
            #Non-decorator version
            @dispatch
            def add_return_value(func, additional):
                def wrapper(*args, **kwargs):
                    return func(*args, **kwargs) + additional
                return wrapper
        
            #decorator version.
            @add_return_value.dispatch
            def add_return_value(additional):
                def decorator(func):
                    return add_return_value(func, additional)
                return decorator
        
            plus_one_len = add_return_value(len, 1)
            assert plus_one_len([1, 2, 3]) == 4
        
            @add_return_value(10)
            def double_add_10(x):
                return x * 2
        
            assert double_add_10(5) == 20
        
        
Platform: any
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.3
Classifier: Topic :: Software Development
Classifier: Topic :: Software Development :: Libraries
Classifier: Topic :: Software Development :: Libraries :: Python Modules
