1

I am trying to create a function that updates arguments inplace (mostly for curiosity's sake):

def inplaceUpdate(f, inputs):
    for i in inputs:
        i = f(i)

I have three inputs:

x = 1
y = 2
z = 3

And the function f:

f = lambda i: i**2

I would like to run the following code:

inplaceUpdate(f, [x, y, z])

Then I would like for the values of x, y, and z to change inplace. Is this possible?

x = 1
y = 4
z = 9
applecider
  • 2,311
  • 4
  • 19
  • 35
  • @oxfn I did try it, and it does not update `x`, `y`, and `z`, if it did that would've been quite something; 1st time a question would also be an answer ;) – applecider Nov 26 '15 at 13:34

4 Answers4

3

In Python, integers are immutables. There's an on-topic question here.

The idea is that you cannot change the value of the references x, y and z. That means that if you do:

x = 2
y = 3
z = 4
some_func([x, y, z])

There's no way that some_func changes the value of the variables x, y, and z.

However, lists are mutable, and you could do:

def some_func(l):
    l[:] = [i*2 for i in l]

l = [2, 3, 4]
some_func(l)

print l  # the array has changed

And this would indeed change the list. This is because the operation l[:]=... assigns to the containment of the list, instead of reassigning the reference --that would be l=....

Community
  • 1
  • 1
MariusSiuram
  • 3,380
  • 1
  • 21
  • 40
  • I see, this is the right answer, thanks for the reasoning – applecider Nov 26 '15 at 13:43
  • A quick follow up question: is there a way to know if a variable is mutable or not, i.e. `ismutable(x)` which returns a boolean? – applecider Nov 26 '15 at 13:47
  • No. I don't think so. – pppery Nov 26 '15 at 13:47
  • 1
    @applecider the behaviour of being mutable or not depends on the way the programmer has designed the class. For native types, you should know them (and this is enforced in a built-in level). For user-defined classes, it depends on the initialization and its methods. – MariusSiuram Nov 26 '15 at 13:54
2

Seems, what you whant is to map a list. There is beautiful builtin function map for that

# Declare lambda somewhere
f = lambda i: i**2

# Map your inputs
input = [1, 2, 3]
result = map(f, input)
oxfn
  • 6,590
  • 2
  • 26
  • 34
  • Thanks for the points, I was aware of maps, but I would like to inplace update, i.e. not use an equal sign, x, y, and z are complicated objects that I don't want to put together into a list, I want to keep them as separate variables but run the same operation on them to update them inplace (yes, I am that lazy, that I don't want to use the equal sign; jk this is more an exercise out of curiosity) – applecider Nov 26 '15 at 13:42
0

You can also use list comprehensions to achieve this. Its more pythonic than map, but does essentially the same thing.

input = [1, 2, 3]
ls = [x**2 for x in input]
Pavlin
  • 5,390
  • 6
  • 38
  • 51
-1

There is no way to modify the values of the variables of the calling function with out using ugly hackery. If you saved a reference to the mutable list you created in [x,y,z], the inplaceUpdate function could modify it.

To accomplish this task using ugly hacks:

def inPlaceUpdate(inputs):
   frame = sys._getframe(1)
   for input in inputs:
       i = f(input)
       for k,v in frame.f_locals.iteritems():
           if v == input:
               frame.f_locals[k] = i
               break
       else:
          for k,v in frame.f_globals.iteritems():
              if v == input:
                 frame.f_globals[k] = i
                 break
pppery
  • 3,731
  • 22
  • 33
  • 46
  • 1
    No. Python language is pass-by-reference. However, some types are immutables, and it behaves just like pass-by-value. But your assertion is false --it only applies to specific types. `int`, `str`, `tuple` but not to `list` or `dict`. – MariusSiuram Nov 26 '15 at 13:43
  • This isn't true. Lists are passed by reference (more correctly, the references are passed by value), and their contents can be modified by the function without any hacks. – interjay Nov 26 '15 at 13:44
  • @MariusSiuram Sorry, I always get confused about pass-by-reference versus pass-by-value. – pppery Nov 26 '15 at 13:44
  • @interjay I already state that, but in the OPs example, modifying the list wouldn't work because he doesn't keep a reference to it. – pppery Nov 26 '15 at 13:45
  • It would work just fine, as you can see in MariusSiuram's answer. You can't modify the list with `lst = other_lst`, but you can modify its contents with `lst[i] = x`. – interjay Nov 26 '15 at 13:47
  • @ppperry If you say pass-by-reference, then it is trivial to modify the variables of the calling function. The problem is the immutability of the types, not the pass-by-reference part. – MariusSiuram Nov 26 '15 at 13:47
  • Even in the current answer state, you are changing the reference stored in the variable used by the caller, but not are changing the contents of the reference itself. If the call stack is deeper, then you are doing some ugly hackery __and__ not achieving the goal. – MariusSiuram Nov 26 '15 at 14:05
  • @MariusSiuram One cannot change the contents of an `int` python object, which is what the reference is pointing to in the question. Also, what do you mean by "If the call stack is deeper, then you are doing some ugly hackery and not achieving the goal". The `inPlaceUpdate` function modifies the variables in the function that directly called it. In what situation would than not be the function whose variables need to be updated? – pppery Nov 26 '15 at 14:13
  • Ok, I was wrong, but your solution feels very mysterious. http://pastebin.com/WiSv7Dsr --it yields curious results, and I dare to say (without real in-depth analysis) that those results are interpreter/execution dependent. I am currently using CPython 2.7.10 and `x_bis` is modified instead of `x`, and with `sys._getframe(1)` nothing happens, and with `sys._getframe(2)` nothing happens in the `do_indirection` function but things change in the main, although not the `x`. – MariusSiuram Nov 27 '15 at 09:23
  • @MariusSiuram From the point of view of my function, all it recieves is the value that needs to be updated, not which variable the value contains. Which variable gets modified is determined by the ordeding of the `f_locals` dictionary. The reason that nothing happened in the `do_indirection` function is that it is being skipped over by the `sys._getframe(2)` call in your example. I have no idea why the a, b, and c variables don't change in `sys._getframe(1)`. – pppery Nov 27 '15 at 14:06