0

after reading several posts here I am still a bit confused on the correct way to implement a Class dynamic attribute with a function as value.

Been some time since I touched python and now I am a bit stuck.

I have the following class:

class RunkeeperUser(object):

    def __init__(self, master):
        self.master = master
        # Get the user methods and set the attributes
        for user_method, call in self.master.query('user').iteritems():
            # Should not get the value but bind a method
            setattr(
                self,
                user_method,
                self.master.query(call)
            )

    def get_user_id(self):
        return self.user_id


    def query(self, call):
        return self.master(call)

Right now as you can see when setting the attribute it directly executes the self.master.query(call) and already results are there when the attribute is accessed.

The question is how can I make this attribute value dynamic upon runtime and not already executed?

I have tried:

setattr(
                self,
                user_method,
                lambda: self.master.query(call)
            )

But that does not work well for some reason. Any help/guidance or best principals to achieve the described result?

Jimmy Kane
  • 16,223
  • 11
  • 86
  • 117
  • Can you elaborate on "does not work well"? Does the function not get called? Do you get an exception and, if so, what is the traceback? – user4815162342 Apr 16 '15 at 11:21
  • @user4815162342 Doesn't contain the correct result. I think it contains something irrelevant from the 1st exmaple. It's an api call, so the 1st implementation if I do eg: ```user.profile``` works ok and has the correct data but using the lambda it posts the last dict call or so. I am confused as well. Sorry. – Jimmy Kane Apr 16 '15 at 11:22
  • @brunodesthuilliers Funny must be it. Also with runkeeper. Thanks checking asap and reporting – Jimmy Kane Apr 16 '15 at 11:26
  • Yes dup. Please close this question! – Jimmy Kane Apr 16 '15 at 11:28

1 Answers1

4

This is a well known gotcha. You have to bind your argument's current value in the lambda, ie:

setattr(
        self,
        user_method,
        lambda call=call: self.master.query(call)
        )
bruno desthuilliers
  • 75,974
  • 6
  • 88
  • 118