Dynamically adding method/state to a class/instance with name/value determined at runtime

Refresh

April 2019

Views

19 time

1

I need to dynamically add a class method with a name determined at runtime, and also an internal state that is determined at runtime. Here is the simplest example I can cook up:

class foo():
    pass

def h(self):   # h() is just a placeholder until we can do setattr()
    state = 'none'
    return state

setattr(h,'state','something')
setattr(foo,'bar',h)
del(h)

print(dir(foo))         # includes 'bar'
print(dir(foo.bar))     # includes 'state'
print(getattr(foo.bar,'state')) # 'something'

f = foo()
print(getattr(f.bar,'state'))    # 'something'

# all is well up to here, but now we go awry
print(f.bar())   # 'none'

In the last line, the bar() return statement seems to be bound to the original definition in h() rather than its new context in foo. I have tried numerous things, and looked at introspection and other topics in stack overflow, but come up empty. How can I modify this code so that the last line yields 'something'?

1 answers

0

You are confusing the local variable state inside h, which has nothing to do with the attribute on the function object, h.state. They are not related... Note, f.bar.state will give you 'something'.

You could could do something like this:

In [6]: class Foo: pass

In [7]: def h(self):
   ...:     return self.state
   ...:

In [8]: Foo.bar = h

In [9]: f = Foo()

In [10]: f.state = 'something'

In [11]: f.bar()
Out[11]: 'something'