def is_unicode_punctuation( str-boolfor in sif unicodedata category( )[ !" "return false return true every unicode character belongs to particular category and each category is identified by two-character identifier all the categories that begin with are punctuation characters here we have used python data types as the annotation expressions but they have no particular meaning for pythonas these calls should make clearutil is_unicode_punctuation("zebr\ "util is_unicode_punctuation( ="!@#?"util is_unicode_punctuation(("!""@")returnsfalse returnstrue returnstrue the first call uses positional argument and the second call keyword argumentjust to show that both kinds work as expected the last call passes tuple rather than stringand this is accepted since python does nothing more than record the annotations in the __annotations__ dictionary if we want to give meaning to annotationsfor exampleto provide type checkingone approach is to decorate the functions we want the meaning to apply to with suitable decorator here is very basic type-checking decoratordef strictly_typed(function)annotations function __annotations__ arg_spec inspect getfullargspec(functionassert "returnin annotations"missing type for return valuefor arg in arg_spec args arg_spec kwonlyargsassert arg in annotations("missing type for parameter 'arg "'"@functools wraps(functiondef wrapper(*args**kwargs)for namearg in (list(zip(arg_spec argsargs)list(kwargs items()))assert isinstance(argannotations[name])"expected argument '{ }of { got { }formatnameannotations[name]type(arg))result function(*args**kwargsassert isinstance(resultannotations["return"])"expected return of { got { }formatannotations["return"]type(result))return result return wrapper