5

__dict__ holds attributes which describe the object. But it shows blank dictionary for function object.

I checked Python: Explain __dict__ attribute here but found no specific answer,though thefourtheye give this answer.

For a class, the variables inside it define the class but for a function, it is not. Then, what exactly defines function?

 def bar(x):
    return x + 1
 print(bar.__dict__) #{}

 class foo(object):
     def bar(x):
         return x + 1
 print(foo.__dict__)  #['bar': <function foo.bar at 0x058E0420>]
jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
Deepak Mishra
  • 91
  • 1
  • 7

2 Answers2

6

A function is defined by its code object: bar.__code__.

If you inspect that (e.g. by dir(bar.__code__)), you will see a variety of variables that describe the parameters of the function, whether it has any constants, what its name is, where it is defined... and finally, what its compiled bytecode is, in bar.__code__.co_code. You can see a human-readable version of this by using the dis module:

import dis
dis.dis(bar)
# =>  2           0 LOAD_FAST                0 (x)
# =>              2 LOAD_CONST               1 (1)
# =>              4 BINARY_ADD
# =>              6 RETURN_VALUE

You can see the variable names like this:

bar.__code__.co_varnames
# => ('x',)

You can read more about the code object in the docs for inspect module. However, most of this is academic - the vast majority of Python programmers will never need to access the code object, or even to know about it.

Amadan
  • 191,408
  • 23
  • 240
  • 301
3

__dict__ returns the attributes of a function - you function has no attributes.

Functions are first class citicens, you can add attributes to them as well:

def bar(x):
    bar.call_count += 1  # increment the functions attribute
    return x*x

print(bar.__dict__)

bar.call_count = 0      # add attribute to function - do not call it before this
print(bar.__dict__)     # you would get an AttributeError trying to access ball_count

bar(4)
bar(5)
bar(6)
print(bar.__dict__)

Output:

{}
{'call_count': 0}
{'call_count': 3}

See Amadan's answer for how to get other informations about the function.


Aside from that:

  • generally you should not use __dunder__ methods - there are high chances you are drifting into xy-Problem-Land if you think you need to, there is probably a better way to achieve what you want to solve
  • all variable that are only declared inside the function are not leaving it's scope - so there is not much need to "get them from the outside" - you can read more about scoping rules here: Short Description of the Scoping Rules? - the short of it is: what's declared inside the function, stays's in the function. The only way to get it, would be returning it from the function or declaring it global (you should avoid polluting your global state).
Patrick Artner
  • 50,409
  • 9
  • 43
  • 69