In Python, everything is object. And every object has member fields that can be accesed. This is stored in special field called __dict__. You can acces object attributes in various ways:
obj.field # direct attribute access
obj.__dict__["field"] # attribute dictionary access
getattr(obj, "field") # get attribute
Functions are objects too and thus they also have a __dict__ field. But they have unique behavior from other objects - if you try access field that doesn't exists with normal object, you will get error. If you try same thing with function, function will add new field instead (like how function create new local variables)
TL;DR: functions are objects too, and they can have fields like objects. These fields don't change between callings
global) to use the variablespreandsucin the function.