This is a pre-production deployment of Warehouse, however changes made here WILL affect the production instance of PyPI.
Help us improve Python packaging - Donate today!
Project Description

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.

import dispatching
greetings = dispatching.DispatchGroup()

To add a function to the dispatch group, decorate it with the dispatch member.

@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:

@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:

@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:

@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.

@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:

@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:

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:

#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:

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
Release History

Release History

1.4.0

This version

History Node

TODO: Figure out how to actually get changelog content.

Changelog content for this version goes here.

Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit.

Show More

1.3.0

History Node

TODO: Figure out how to actually get changelog content.

Changelog content for this version goes here.

Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit.

Show More

1.2.0

History Node

TODO: Figure out how to actually get changelog content.

Changelog content for this version goes here.

Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit.

Show More

1.1.1

History Node

TODO: Figure out how to actually get changelog content.

Changelog content for this version goes here.

Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit.

Show More

1.1.0

History Node

TODO: Figure out how to actually get changelog content.

Changelog content for this version goes here.

Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit.

Show More

1.0.1

History Node

TODO: Figure out how to actually get changelog content.

Changelog content for this version goes here.

Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit.

Show More

1.0

History Node

TODO: Figure out how to actually get changelog content.

Changelog content for this version goes here.

Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit.

Show More

Download Files

Download Files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

File Name & Checksum SHA256 Checksum Help Version File Type Upload Date
Dispatching-1.4.0-py33-none-any.whl (7.6 kB) Copy SHA256 Checksum SHA256 3.3 Wheel Mar 26, 2014
Dispatching-1.4.0.tar.gz (11.3 kB) Copy SHA256 Checksum SHA256 Source Mar 26, 2014

Supported By

WebFaction WebFaction Technical Writing Elastic Elastic Search Pingdom Pingdom Monitoring Dyn Dyn DNS Sentry Sentry Error Logging CloudAMQP CloudAMQP RabbitMQ Heroku Heroku PaaS Kabu Creative Kabu Creative UX & Design Fastly Fastly CDN DigiCert DigiCert EV Certificate Rackspace Rackspace Cloud Servers DreamHost DreamHost Log Hosting