Function attributes in Python
It's well known that in Python, every function is a first-class object, which gives us the ability to pass them as arguments, assign to variables, compare to each other and return from other functions. But what about rarely used custom function attributes?
Every function has a number of additional attributes which can be accessed using dot syntax (e.g.
func.__name__). The dir built-in function returns a list of available attributes of a specified object.
Since Python 2.1, functions can have arbitrary attributes, that is, you can use a function as key-value storage.
def func(): print(func.a) func.a -= 10 func.a = 10 func.foo = "bar" func() func.a += 2 func() print(func.__dict__)
Internally, it's just a dictionary that handles failed attribute lookups (i.e., nondefault attributes). You can access or even replace such dictionary using
__dict__ attribute. PEP 232 has an extensive description of this feature.
For example, you can track the number of times a function was called:
def func(a, b): func.ncalls += 1 return a + b func.ncalls = 0 func(1, 2) func(3, 2) print(func.ncalls)
Or you can use it to cache results of a function:
def cached_sum(a, b): key = (a, b) if key not in cached_sum.cache: cached_sum.cache[key] = a + b return cached_sum.cache[key]
You can find such a technique in popular Python projects. In general, it's better to avoid using this because it makes people confused and requires extra comments to explain the behavior.