2
class TestClass(object):
    def __init__(self):
        self.value = 100
        self.x = lambda: self.value.__add__(100)
        self.run()

    def run(self):        
        self.x()
        print self.value

t = TestClass()

#Output: 100

I would like to able to define a lambda function such as the one in TestClass and have it alter an instance variable. It would seem that the way the lambda is constructed means that it does not modify the original value. I suspect that this to do with Python's reference strategy which I do more or less understand.

So accepting the flaws in what I have done, is there a similar way to get similar functionality? I ultimately need to define many methods like x and intend to keep them in a dictionary as they will form a simple instruction set. As far as I can tell I need either to use lambdas or exec to do what I want.

sheepez
  • 986
  • 1
  • 10
  • 26
  • Are you sure you need to use lambdas? There is no reason you cannot store a reference to a function defined with the `def` statement in a dictionary. – chepner May 15 '12 at 21:29
  • @chepner In that sense I do not need to use `lambda` but if I can do it this way the source will be a lot more readable. Well, it will at least be a lot more readable to my eye. – sheepez May 15 '12 at 21:33
  • If the methods are short, you can always write `def x(self): return something` on one line. If you post some of the code you use to store your methods in a dictionary, we can figure out if lambdas are really necessary or useful. – chepner May 15 '12 at 21:35

2 Answers2

7

__add__ is not inplace, so the return value of TestClass.x is self.value + 100, but self.value is not altered. Try this:

import random
HATE_LAMBDAS = random.choice(True, False)
class TestClass(object):
    def __init__(self):
        self.value = 100
        if HATE_LAMBDAS:
            def x():
                self.value += 100
            self.x = x
        else:
            self.x = lambda: setattr(self, "value", self.value + 100)
        self.run()

    def run(self):        
        self.x()
        print self.value

t = TestClass()

#Output: 200

Use the setattr to increment the value while still using a lambda. Beware however, lambda's in python are one of its worst features. However, both methods work.

Edit

Just remebered something that you might find usefull! The standard library has a module called operator which implements standard operators as functions. If you plan on using lambdas a lot, you might like to investigate it.

BluePeppers
  • 1,603
  • 14
  • 12
  • Thanks, that's cleared up quite a lot. Why are you so anti-lambda? – sheepez May 15 '12 at 21:43
  • Lambda's are restricted in what they can do. The following isn't valid: `lambda x: self.value = x + 100`. Neither is `lambda x: print x`. In other languages, lambdas are much more powerfull – BluePeppers May 15 '12 at 21:43
  • That is true, and given that I am having to write some convoluted code to allow it to fit into lambdas I am seriously considering dropping them. – sheepez May 15 '12 at 21:47
  • That edit is really useful, that might ease some of the wrangling if I pursue this method. – sheepez May 15 '12 at 21:50
  • No problem :) But it won't help you get around python reference semantics, so you'll need to use `setattr` or some other function if you want side effects. – BluePeppers May 15 '12 at 21:53
  • 1
    The edit is useful, but not for this problem. Note how you still need to assign the result of `iadd(x, y)` to the `x` in order to emulate `x += y`. No Python function can modify its arguments the way you'd *expect* `iadd` to work, if it could. – cvoinescu May 15 '12 at 21:56
  • The edit was more because I noticed that the OP was using lambdas and mentioned implementing an instruction set. – BluePeppers May 15 '12 at 21:57
  • Just trying to save the OP some time in figuring out why calling `iadd(x, y)` does not modify `x`. But you did too, while I was typing. :) – cvoinescu May 15 '12 at 21:59
  • +1 changed to -0 as you deleted the clearer non-lambda version of your answer. I prefer `def x(): self.value += 100` and then the next line `self.x = x` . Even better would be a "private" instance method `def __x(self): self.value += 100`. – Steven Rumbalski May 15 '12 at 22:00
  • @StevenRumbalski See latest version – BluePeppers May 15 '12 at 22:05
  • @sheepez lambdas should not be used just for the sake of using them. However, using a dictionary that contains mapping to functions as shown by Chepner below is quite a nice approach. Use lambdas when you can use one-liners that don't sacrifice readability, which means wherever a lambda is actually more readable than a regular method. An example of this might be square_root(x). – Arnab Datta Jul 12 '12 at 13:03
2

I'm just guessing at what you want to accomplish, but no lambdas necessary.

class TestClass(object):
    def __init__(self):
        self.value = 100
        self.methods = { 'add':      self.w,
                         'subtract': self.x,
                         'mult':     self.y,
                         'div':      self.z,
                       }
        self.run()

    def w(self): self.value += 100
    def x(self): self.value -= 100
    def y(self): self.value *= 100
    def z(self): self.value /= 100


    def run(self):        
        self.x()
        print self.value
chepner
  • 497,756
  • 71
  • 530
  • 681
  • My only reservation about that approach is that it will make adding items to the dictionary at runtime a little trickier (I think). – sheepez May 15 '12 at 21:45