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:
- behavior of an assignment versus a reference
- 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.