run on your own to see len(dir( ) [ for in dir(fif not startswith('__')[ :\codepy - def ()pass dir(frun on your own to see len(dir( ) [ for in dir(fif not startswith('__')['func_closure''func_code''func_defaults''func_dict''func_doc''func_globals''func_name'if you're careful not to name attributes the same wayyou can safely use the function' namespace as though it were your own namespace or scope as we saw in that such attributes can be used to attach state information to function objects directlyinstead of using other techniques such as globalsnonlocalsand classes unlike nonlocalssuch attributes are accessible anywhere the function itself iseven from outside its code in sensethis is also way to emulate "static localsin other languages--variables whose names are local to functionbut whose values are retained after function exits attributes are related to objects instead of scopes (and must be referenced through the function name within its code)but the net effect is similar moreoveras we learned in when attributes are attached to functions generated by other factory functionsthey also support multiple copyper-calland writeable state retentionmuch like nonlocal closures and class instance attributes function annotations in in python (but not )it' also possible to attach annotation information--arbitrary user-defined data about function' arguments and result--to function object python provides special syntax for specifying annotationsbut it doesn' do anything with them itselfannotations are completely optionaland when present are simply attached to the function object' __annotations__ attribute for use by other tools for instancesuch tool might use annotations in the context of error testing we met python ' keyword-only arguments in the preceding annotations generalize function header syntax further consider the following nonannotated functionwhich is coded with three arguments and returns resultdef func(abc)return function objectsattributes and annotations