Reputation: 164
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
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
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
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