Search code examples
pythonclosuresgetattrsetattr

Why does setattr not affect the return value?


I am using setattr() to monkey patch a closure. Using getattr() shows that the closure was patched correctly. However, the return value is unaffected.

>>> def foo():
...     def bar():
...             return('bar')
...     return(bar())
... 
>>> def baz():
...     return('baz')
... 
>>> setattr(foo, 'bar', baz)
>>> bar = getattr(foo, 'bar')
>>> bar()
'baz'
>>> foo()
'bar'

After using setattr() I expect foo() to return 'baz'; but, it returns 'bar' as if the patch never happened.


Solution

  • It did work, just not as you're expecting:

    f = foo.bar
    
    print(f())  # baz
    

    bar is a nested function inside foo; not an attribute of it. As far as I know, there is no way of reassigning an inner function like this.

    Your best best is probably to have an externally-accessible variable that foo relies on, and reassign that as needed. Or give it a mutable object that you mutate externally into a desired state. I can't say I'd recommend these options, but given the current requirements, they should work.