#!/usr/bin/env pythonfrom types import ClassType#we adopt the null object pattern in the (unlikely) case#that __class__ is None for some strange reason_NO_CLASS=object()def get_object_type(obj):obj_type = getattr(obj, "__class__", _NO_CLASS)if obj_type is not _NO_CLASS:return obj_type# AFAIK the only situation where this happens is an old-style classobj_type = type(obj)if obj_type is not ClassType:raise ValueError("Could not determine object '{}' type.".format(obj_type))return obj_type
def foo(obj):"""given a string with items separated by spaces,or a list or tuple,do something sensible"""if isinstance(obj, str):obj = str.split()return _foo_handles_only_lists_or_tuples(obj)
from collections import Iterablefrom numbers import Number
def bar(obj):"""does something sensible with an iterable of numbers,or just one number"""if isinstance(obj, Number): # make it a 1-tupleobj = (obj,)if not isinstance(obj, Iterable):raise TypeError('obj must be either a number or iterable of numbers')return _bar_sensible_with_iterable(obj)
def baz(obj):"""given an obj, a dict (or anything with an .items method)do something sensible with each key-value pair"""for key, value in obj.items():_baz_something_sensible(key, value)
def do_something(arg):if isinstance(arg, int):... # some code specific to processing integersif isinstance(arg, str):... # some code specific to processing stringsif isinstance(arg, list):... # some code specific to processing lists... # etc
下面是它如何工作的一个小例子:
from functools import singledispatch
@singledispatchdef say_type(arg):raise NotImplementedError(f"I don't work with {type(arg)}")
@say_type.registerdef _(arg: int):print(f"{arg} is an integer")
@say_type.registerdef _(arg: bool):print(f"{arg} is a boolean")
>>> say_type(0)0 is an integer>>> say_type(False)False is a boolean>>> say_type(dict())# long error traceback ending with:NotImplementedError: I don't work with <class 'dict'>