Accueil / Blog / Métier / Archives / Python check arguments types

Python check arguments types

Par mle — publié 10/06/2010, édité le 11/03/2015
Decorators help us wrap some routines at function invocation

Decorators help us wrap some routines at function invocation. Here I show a small example that raises TypeError exceptions when given args have unexpected type. Note that it is not pythonic to type check.

This recipe is quite old, as its first pieces appear in PEP-0318 in 2003. A module exists too but it looks neglected...

The (heretic) decorator itself !

def accepts(*argstypes, **kwargstypes):
    def wrapper(func):
        def wrapped(*args, **kwargs):
            if len(args) > len(argstypes):
                raise TypeError("%s() takes at most %s non-keyword arguments (%s given)" % (func.__name__, len(argstypes), len(args)))
            argspairs = zip(args, argstypes)
            for k,v in kwargs.items():
                if k not in kwargstypes:
                    raise TypeError("Unexpected keyword argument '%s' for %s()" % (k, func.__name__))
                argspairs.append((v, kwargstypes[k]))
            for param, expected in argspairs:
                if param is not None and not isinstance(param, expected):
                    raise TypeError("Parameter '%s' is not %s" % (param, expected.__name__))
            return func(*args, **kwargs)
        return wrapped
    return wrapper

Let us decorate !

>>> @accepts(str, arg2=int)
... def f(arg1, arg2=None):
...     pass
...

See it in action...

>>> f('foo')
>>> f('foo', arg2=3)
>>> f()
TypeError: f() takes at least 1 argument (0 given)
>>> f('foo', 'bar')
TypeError: f() takes at most 1 non-keyword arguments (2 given)
>>> f('foo', arg2='bar')
TypeError: Parameter 'bar' is not int
>>> f('foo', arg3='bar')
TypeError: Unexpected keyword argument 'arg3' for f()

Or with classes...

>>> class A(object):
...     pass
...
>>> class B(object):
...     @accepts(object, (str, unicode))
...     def f(self, s):
...         pass
...
...     @accepts(object, A)
...     def g(self, a):
...         pass

>>>
>>> b = B()
>>> b.f(u'foo')
>>> b.f('foo')
>>> b.g(A())
>>> b.g(B())
TypeError: Parameter '<__main__.b object="" at="">' is not A

The same can be applied to return :)

def returns(rtype):
    def wrapper(f):
        def wrapped(*args, **kwargs):
            result = f(*args, **kwargs)
            if not isinstance(result, rtype):
                raise TypeError("return value %r does not match %s" % (result,rtype))
            return result
        return wrapped
    return wrapper
>>> @accepts(str, arg2=int)
... @returns(int)
... def f(arg1, arg2=None):
...     return 0
...

..but kids, don't do this at home :-)

ABONNEZ-VOUS À LA NEWSLETTER !
Voir aussi
Lancement d'une formation au Machine Learning Lancement d'une formation au Machine Learning 21/11/2017

Cette formation présente le domaine du Machine Learning, au travers de l'écosystème scientifique ...

Machine Learning : classer automatiquement vos données à l'import Machine Learning : classer automatiquement vos données à l'import 20/03/2018

Comment utiliser des algorithmes de machine learning pour importer correctement des données dans ...

Superset, l'outil de DataViz de AirBnB Superset, l'outil de DataViz de AirBnB 01/03/2018

Superset est un outil développé par AirBnB. Son objectif consiste à faciliter la prise de ...

Scraping & Machine Learning : comment fonctionne un moteur de recherche ? Scraping & Machine Learning : comment fonctionne un moteur de recherche ? 22/01/2018

Ou comment utiliser des composants libres pour faire votre mini-Google (ou Qwant)

Découvrez la formation initiation au Python Scientifique Découvrez la formation initiation au Python Scientifique 24/11/2017

La formation initiation au Python scientifique vous permettra de vous initiez à la programmation ...