all pargs match first expected args by position the rest must be in kargs or be omitted defaults expected list(allargspositionals expected[:len(pargs)for (argname(lowhigh)in argchecks items()for all args to be checked if argname in kargswas passed by name if kargs[argnamehigherrmsg '{ argument "{ }not in { { }errmsg errmsg format(funcnameargnamelowhighraise typeerror(errmsgelif argname in positionalswas passed by position position positionals index(argnameif pargs[positionhigherrmsg '{ argument "{ }not in { { }errmsg errmsg format(funcnameargnamelowhighraise typeerror(errmsgelseassume not passeddefault if traceprint('argument "{ }defaultedformat(argname)return func(*pargs**kargsreturn oncall return ondecorator okrun original call the following test script shows how the decorator is used--arguments to be validated are given by keyword decorator argumentsand at actual calls we can pass by name or position and omit arguments with defaults even if they are to be validated otherwise""file rangetest_test py ( xcomment lines raise typeerror unless "python -oused on shell command line ""from __future__ import print_function from rangetest import rangetest test functionspositional and keyword @rangetest(age=( )persinfo rangetest)(persinfodef persinfo(nameage)print('% is % years old(nameage)@rangetest( =( ) =( ) =( )def birthday(mdy)print('birthday { }/{ }/{ }format(mdy)persinfo('bob' persinfo(age= name='bob' decorators