0

In Python, I find the following behavior of function related to the variable scope somewhat puzzling. It seems that a function can alter an element of an array outside of the function but not replace the array completely. What is this operating principle?

a = np.array([2,3,5])
b = np.array([2,3,5])

def fun1():
    a[1] = 100
    return

def fun2():
    b = -1.1
    return

fun1()
print(a)

fun2()
print(b)
Hans
  • 1,269
  • 3
  • 19
  • 38
  • Can you clarify what you are asking? Are you asking what the rules are for assignment scope? Are you asking why the rules as they are result in this behaviour? Are you asking why this behaviour is deemed desirable? – MisterMiyagi Feb 09 '21 at 19:32
  • 3
    The key thing you are missing here is that *assignment never mutates*. Simple assignment , `b = -1.1` simply binds a local variable, `b` to the value `-1.1`. On the other hand, `fun1` uses `a[1] = 100`, which is actually just a call to `a.__setitem__(1, 100)`, which is a mutator method. A good overview: https://nedbatchelder.com/text/names.html – juanpa.arrivillaga Feb 09 '21 at 19:32
  • "but not replace the array completely." That doesn't make any sense. This isn't how python variables work. Variables are names that refer to objects in a given namespace. You can *change what the name refers to*, but that doesn't "replace" the object. You can think of variables as nametags that you can place on objects, and move around at will without changing anything about the actual object – juanpa.arrivillaga Feb 09 '21 at 19:34
  • Does this answer your question? [Why does writing to a variable change its scope?](https://stackoverflow.com/questions/64801735/why-does-writing-to-a-variable-change-its-scope) – MisterMiyagi Feb 09 '21 at 19:35
  • Does this answer your question? [Short description of the scoping rules?](https://stackoverflow.com/questions/291978/short-description-of-the-scoping-rules) – MisterMiyagi Feb 09 '21 at 19:35
  • @juanpa.arrivillaga It is not exactly clearcut that "assignment never mutates". Assignment of global, class and closure variables mutates the corresponding namespace. Especially global and class scopes can be accessed as first-class objects, making the mutation visible beyond implementation details. – MisterMiyagi Feb 09 '21 at 19:41
  • @MisterMiyagi it doesn't *mutate the object being assigned*. People from other langauges have an intution that something like `x = [1,2,3]`; `x = [2, 4, 6]` is mutating the object, so if you had other references to that object, it would be visible there too – juanpa.arrivillaga Feb 09 '21 at 19:42
  • @MisterMiyagi so, here's a C-program that demonstrates the behavior that some people expect in Python: https://repl.it/@juanpa_arrivillaga/MealyGrowlingViruses#main.c – juanpa.arrivillaga Feb 09 '21 at 19:56
  • @juanpa.arrivillaga Yes, [I know they do](https://stackoverflow.com/questions/13530998/are-python-variables-pointers-or-else-what-are-they). Do I really have to write a metaclass just to prove a point? – MisterMiyagi Feb 09 '21 at 20:03
  • @MisterMiyagi: I am asking what the rules are for assignment scope. – Hans Feb 09 '21 at 20:21
  • @Hans the assignment scope follow the LEGB order, Local, Enclosing, Global, Bulit-in Scope, since b=1 is a assignment it goes straight to the first scope, since a[1] is a update it looks for a variable bottom up, L first E, G B, if there is none the operation throws a error, i didnt knew what you wanted to know so i didnt include that in my answer – zero Feb 09 '21 at 20:32
  • @Hans assignment is automatically local, unless you use a `global` or `nonlocal` statement – juanpa.arrivillaga Feb 09 '21 at 20:34
  • @zero: Thank you. It would be helpful if you include the LEBG order you mentioned in your answer. – Hans Feb 09 '21 at 22:07
  • @Hans you're welcome, i tried to update the answer a little, i hope it helps – zero Feb 10 '21 at 02:29

1 Answers1

1

Python scope go in the LEGB order, First checking Local, Enclosing, Global Scope, and Bult-in scope When you search inside a array element, python searchs for a existing variable and references it, since there is no variable inside the function scope it goes to up in the scope

def fun3():
    c[0] = 0
    return

fun3 would print a error C is not defined wouldn't make c = [0], it would try to find the variable C first in the local scope (inside the function in the case) after it will go up in scope for each search

but when you do b = 1.1, it is going straight to assigning the variable it prioritizes the local scope and simple define its value inside the function

def fun5():
     b = -1.1
     print(b) # prints local value, -1.1
     return
print(b) #prints original array)

in the mean while

def fun6():
    b = [2,3,4]
    b[1] = 500
    print(b) #would print [2,500,4]
    return
print(b) #would print original array

now in fun6 since the new b array is in inside the scope, the b[1] operation references the local scope first, and them only changes the local array without changing the original b array this happens because its the closer reference to b is in the local scope. if you comment the first line, the next closer reference would be the original b declared in the beginning of the file therefore the change would affect the variable b of that scope

user juanpa.arrivillaga also mentioned it on a reply first

zero
  • 172
  • 1
  • 6
  • "declaring syntax" is not standard terminology. Python *doesn't really have variable declarations* (unless you count variable annotations) – juanpa.arrivillaga Feb 09 '21 at 19:45
  • yes, is not standard terminology, was more a simple way to explaining instead of deep diving the python interpreter, neither is mutate syntax, but i thought was pretty obvious what meant in the context, i can change it but i'm not even sure if thats the main thing OP wants as a answer @juanpa.arrivillaga – zero Feb 09 '21 at 19:49
  • Well, I don't think saying "declaring" which has a specific meaning in other languages which doesn't exist in Python simplifies anything, you don't need a deep dive into the interpreter. In many languages, you can declare variables, and you can assign to variables. In Python, you can only assign to variables – juanpa.arrivillaga Feb 09 '21 at 19:55
  • 1
    @juanpa.arrivillaga yes you are correct. i meant, on python you can only assign or call naming a variable, yes, you cant simple do a int b; and declare a variable to be assigned later, what i meant in deep diving the interpreter is to see which inside functions x[0] = calls vs which functions x = calls inside the python interpreter – zero Feb 09 '21 at 20:03