Function and Its Attributes
Function Attributes
Functions in Python are objects of a specific class. Like any other object, they have attributes that can be accessed via dot notation: object.name
.
def foo(a: int, b: int = 2,*, c: bool = True) -> int: """Docstring""" if c: return a + b return a - b print(foo.__name__, foo.__class__) # foo <class 'function'> print(foo.__doc__) # Docstring print(foo.__module__) # __main__ print(foo.__annotations__) # {'a': <class 'int'>, 'b': <class 'int'>, 'c': <class 'bool'>, 'return': <class 'int'>} print(foo.__defaults__) # positional # (2,) print(foo.__kwdefaults__) # keyword-only # {'c': True}
Built-in functions also have attributes.
print(print.__name__, print.__class__) # print <class 'builtin_function_or_method'> print(print.__doc__) # Prints the values to a stream, or to sys.stdout by default. ... print(print.__module__) # builtins print(print.__text_signature__) # ($module, /, *args, sep=' ', end='\n', file=None, flush=False)
Adding Attributes to a Function
User-defined functions also allow getting and setting arbitrary attributes. We can add and modify attributes in the function body or later when we use it at runtime.
def foo(x): foo.attr1 = x foo(0) print(foo.attr1) # 0 foo.attr1 = 1 print(foo.attr1) # 1 foo.attr2 = 2 print(foo.attr2) # 2
We can use other Python objects as function attributes.
def foo(x): def f1(): return x foo.x = x foo.f1 = f1 foo(3) print(foo.x) # 3 print(foo.f1()) # 3 foo.x = 8 print(foo.x) # 8 print(foo.f1()) # 3 print(foo.__dict__) # {'x': 8, 'f1': <function foo.<locals>.f1 at 0x000002361F03CB80>}
Functions and AttributeError
1. CPython does not support arbitrary function attributes for built-in functions.
sorted.attr = 1 # AttributeError: 'builtin_function_or_method' object has no attribute 'attr'
2. A function attribute defined inside a function does not exist until that function is called.
def foo(): foo.attr = 1 print(foo.attr) # AttributeError: 'function' object has no attribute 'attr'
3. Like function objects, bound method objects support getting attributes. But to set a method attribute, you need to explicitly set it on the underlying function object.
class A: def method(self): pass a = A() print(A.method) # <function A.method at 0x00000247307ECB80> print(a.method) # <bound method A.method of <__main__.A object at 0x000002472DF4AC50>> # underlying function object print(a.method.__func__) # <function A.method at 0x00000247307ECB80> a.method.attr = 1 # AttributeError: 'method' object has no attribute 'attr' # set attribute a.method.__func__.attr = 1 # get attribute print(a.method.attr) # 1
References: