len("asdf")
4
len([1, 2, 3, 4, 5])
5
The above works because len()
actually calls the __len__
special method on its argument.
[1, 2, 3, 4, 5].__len__()
5
Alternatively, you can do it by hand.
def p(arg):
if isinstance(arg, list):
print("a list:")
for e in enumerate(arg):
print("{}: {}".format(*e))
elif isinstance(arg, str):
print("a string:", arg)
else:
print("an unknown object:", repr(arg))
p([1, 2, 3, 4, 5]), p({})
a list: 0: 1 1: 2 2: 3 3: 4 4: 5 an unknown object: {}
(None, None)
from functools import singledispatch
@singledispatch
def pp(arg, verbose=False):
print("an object:", repr(arg))
pp("asdf"), pp(123), pp([])
an object: 'asdf' an object: 123 an object: []
(None, None, None)
@pp.register(list)
def pp_list(arg):
print("a list:")
for e in enumerate(arg):
print("{}: {}".format(*e))
pp("asfd")
an object: 'asfd'
pp([1, 2, 3, 4, 5])
a list: 0: 1 1: 2 2: 3 3: 4 4: 5
The register
decorator returns the undecorated function, so types can be stacked:
@pp.register(int)
@pp.register(float)
def pp_number(obj):
print("a number:", obj)
pp(1)
a number: 1
pp(1.0)
a number: 1.0
Call register
on existing or anonymous functions:
pp.register(type(None), lambda _: print("nothing"))
<function __main__.<lambda>>
pp(None)
nothing
Which specific function would be called?
pp.dispatch(list)
<function __main__.pp_list>
pp.dispatch(int)
<function __main__.pp_number>
The MRO is used to handle unknown types. The function decorated with singledispatch
is used for object
.
pp.dispatch(dict)
<function __main__.pp>
pp.registry.keys()
dict_keys([<class 'list'>, <class 'NoneType'>, <class 'object'>, <class 'float'>, <class 'int'>])
There is a backport on pypi and an older implementation in the pkgutil module in Python 2 (not exportet via __all__
):
from pkgutil import simplegeneric