Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python functions can be given new attributes from outside the scope?

I didn't know you could do this:

def tom():
    print "tom's locals: ", locals()

def dick(z):
    print "z.__name__ = ", z.__name__
    z.guest = "Harry"
    print "z.guest = ", z.guest
    print "dick's locals: ", locals()

tom()              #>>> tom's locals:  {}
#print tom.guest    #AttributeError: 'function' object has no attribute 'guest'
print "tom's dir:", dir(tom)  # no 'guest' entry

dick( tom)         #>>> z.__name__ =  tom
                   #>>> z.guest =  Harry
                   #>>> dick's locals:  {'z': <function tom at 0x02819F30>}
tom()              #>>> tom's locals:  {}
#print dick.guest  #AttributeError: 'function' object has no attribute 'guest'

print tom.guest    #>>> Harry
print "tom's dir:", dir(tom)  # 'guest' entry appears

Function tom() has no locals. Function dick() knows where tom() lives and puts up Harry as 'guest' over at tom()'s place. harry doesn't appear as a local at tom()'s place, but if you ask for tom's guest, harry answers. harry is a new attribute at tom().

UPDATE: From outside tom(), you can say "print dir(tom)" and see the the tom-object's dictionary. (You can do it from inside tom(), too. So tom could find out he had a new lodger, harry, going under the name of 'guest'.)

So, attributes can be added to a function's namespace from outside the function? Is that often done? Is it acceptable practice? Is it recommended in some situations? Is it actually vital at times? (Is it Pythonic?)

UPDATE: Title now says 'attributes'; it used to say 'variables'. Here's a PEP about Function Attributes.

like image 244
behindthefall Avatar asked Feb 05 '26 12:02

behindthefall


2 Answers

I think you might be conflating the concepts of local variables and function attributes. For more information on Python function attributes, see the SO question Python function attributes - uses and abuses.

like image 198
Greg Hewgill Avatar answered Feb 07 '26 03:02

Greg Hewgill


@behindthefall, the motivation to give function objects generic assignable attributes (they didn't use to have them) was that, absent such possibilities, real and popular frameworks were abusing what few assignable attributes existed (typically __doc__) to record information about each given function object. So there was clearly a "pent-up demand" for this functionality, so Guido decided to address it directly (adding an optional dict to each function object to record its attributes isn't a big deal -- most function objects don't need it, and it is optional, so the cost is just 4 bytes for a null pointer;-).

Assigning such attributes in arbitrary places would be very bad practice, making the code harder to understand for no real benefit, but they're very useful when used in a controlled way -- for example, a decorator could usefully record all kinds of things about the function being decorated, and the context in which the decoration occurred, as attributes of the wrapper function, allowing trivially-easy introspection of such metadata to occur later at any time, as needed.

As other answers already pointed out, local variables (which are per-instance, not per-function object!) are a completely disjoint namespace from a function object's attributes held in its __dict__.

like image 43
Alex Martelli Avatar answered Feb 07 '26 04:02

Alex Martelli



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!