Home > Back-end >  Python list (and other objects) change when indexed inside a function [duplicate]
Python list (and other objects) change when indexed inside a function [duplicate]

Time:09-24

My (limited) understanding of Python is that objects defined outside a function should remain the same even if modified inside a function, i.e.

def fun():
    i=1
    return('done')

i=0
fun()
i==0 ## True

However, lists (and other objects like numpy arrays) change when indexed inside a function:

def fun():
    img[0] = img[0]   100 
    return('done')

img = [0, 1]
fun()
img == [0, 1] ## False

Obviously I am missing a core concept with respect to how global and local variables are handled inside functions but can't seem to find any information online. Could someone please explain why objects change inside functions when indexed? Also, could someone describe how to avoid this "feature" so that when I index objects (lists, arrays, etc...) within a function, I don't inadvertently change the objects defined outside that function? Thanks!

CodePudding user response:

see this example:

class Person:
  def __init__(self, name):
    self.name = name
  def set_name(self, new_name):
    self.name = new_name


def set_alex():
  p.set_name("alex")

p = Person()
print(p.name) # not alex
set_alex()
print(p.name) # alex

as you can see, the set_name method change its object state.

when you do x[0] = ..., python call the __setitem__ method from the x object, behind the scenes.
so you are actually calling __setitem__ method from x, then inside the method, it change the x state.

but...

def set_alex():
  name = "alex"

name = "not alex"
print(name) # not alex
set_alex()
print(name) # not alex

why doesn't this do the same?
because name refers to local variable in the function set_alex.
so python does not store the string "alex" into global variable name.
you can use the global keyword to refers global variable, for example:

def set_alex():
  global name
  name = "alex"

print(name) # alex

why does x[0] calls the __setitem__ method?
python has a feature called operator overloading

CodePudding user response:

Please see my recent answer to a closely related question: https://stackoverflow.com/a/69303154/8431111

There's two concepts in play for your example:

  1. behavior of an assignment versus a reference
  2. mutating a single container object

For item (1.) when fun assigns i = 1, it creates a new local variable due to the lack of a global declaration.

For item (2.) let's consider this slightly simpler code instead, as it doesn't change the essential problem:

    img[0] = 100 

The assignment operator locates img by first consulting the function's local scope (not found) and then finding it in the module's global scope. With a reference to the existing img object in hand, it then calls __setitem__ to alter what the zero-th element points to. In this case it will point at an immutable int object. The setter's assignment is performed by a STORE_SUBSCR bytecode instruction.

  • Related