Abhishek
Abhishek

Reputation: 164

Appending an attribute to a function in Python

I am not sure exactly what this means or how it is used, but I came across this functionality when it comes to a function. I am able to dynamically add attributes to a function.

What is the use of this and how does it happen? I mean it's a function name after all, how can we add attributes to it dynamically?

def impossible():
    print "Adding a bool"

impossible.enabled = True 
# I was able to just do this. And this is a function, how does this add up?

print(impossible.enabled) # No attribute error. Output: True

Upvotes: 1

Views: 2949

Answers (3)

user9611000
user9611000

Reputation:

You can, for example, use a function attribute to implement a simple counter, like so:

def count():
    try:
        count.counter += 1
    except AttributeError:
        count.counter = 1
    return count.counter

Repeatedly calling "count()" yields: 1, 2, 3, ...

Upvotes: 0

AntiMatterDynamite
AntiMatterDynamite

Reputation: 1512

in python functions are objects, they have all sorts of inner attributes and they can also have the __dict__ attribute, and like any other object anything in __dict__ is a variable of that object.you can see it if you print it before and after impossible.enabled

def impossible():
    print "Adding a bool"

print(impossible.__dict__) #  {}
impossible.enabled = True 
print(impossible.__dict__) #  {'enabled': True}

this doesn't change the function in any way since most of the time __dict__ is empty and holds no special value in a function. in fact its a bit useful since you could use this in a function to store static variables without cluttering your global names

Upvotes: 3

MatsLindh
MatsLindh

Reputation: 52832

The name impossible points to an object that represents the function. You're setting a property on this object (which python allows you to do on all objects by default):

>>> def foo():
...   print("test")
...
>>> dir(foo)
['__call__', ..., 'func_closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_name']
>>> foo.a = 'test'
>>> dir(foo)
['__call__', ..., 'a', ...]

Since this object implements __call__, it can be called as a function - you can implement your own class that defines __call__ and it'll also be allowed to be called as a function:

>>> class B:
...   def __call__(self, **kw):
...     print(kw)
...
>>> b = B()
>>> b()    
{}
>>> b(foo='bar')
{'foo': 'bar'}

If you create a new function, you can see that you haven't done anything to the definition of a function (its class), just the object that represents the original function:

>>> def bar():
...   print("ost")
...
>>> dir(bar)
['__call__', ..., 'func_closure', ...] 

This new object does not have a property named a, since you haven't set one on the object bar points to.

Upvotes: 0

Related Questions