Pritam
Pritam

Reputation: 1029

python inner functions treat mutable vs immutable variables differently

I am trying to understand why does the inner function has access to the outer list (arr) but not the outer boolean variable (found).

def outer():
    arr = [1, 2, 3]
    found = False
    print("outer func ids: ", id(arr), id(found))
    def inner(num):
        arr.append(4)
        found = True
        print("inner func ids:", id(arr), id(found))
    inner(3)
    print("outer func ids: ", id(arr), id(found))
    return found
outer()

Output:

('outer func ids: ', 4536180248, 140736008926072)
('inner func ids:', 4536180248, 140736008926048)
('outer func ids: ', 4536180248, 140736008926072)

Can someone please clarify. Why does the list have the same id even though we are doing append operation in the inner function ?

Upvotes: 0

Views: 196

Answers (3)

yoonghm
yoonghm

Reputation: 4625

From python Faq

Python, variables that are only referenced inside a function are implicitly global. If a variable is assigned a value anywhere within the function’s body, it’s assumed to be a local unless explicitly declared as global.

Though a bit surprising at first, a moment’s consideration explains this. On one hand, requiring global for assigned variables provides a bar against unintended side-effects. On the other hand, if global was required for all global references, you’d be using global all the time. You’d have to declare as global every reference to a built-in function or to a component of an imported module. This clutter would defeat the usefulness of the global declaration for identifying side-effects.

Try not to assign value to found and see its id.

Let's see some examples:

a = [1, 2, 3]
b = True
c = 123
d = "Hello"

def print_global1():
  print("print_global1: a=", a, id(a))
  print("print_global1: b=", b, id(b))
  print("print_global1: c=", c, id(c))
  print("print_global1: d=", d, id(d))

def print_global2():
  global a, b, c, d
  print("print_global2: a=", a, id(a))
  print("print_global2: b=", b, id(b))
  print("print_global2: c=", c, id(c))
  print("print_global2: d=", d, id(d))

def print_global3():
  global a, b, c, d
  a.append(4)
  b = False
  c += 1
  d = d.upper()
  print("print_global3: a=", a, id(a))
  print("print_global3: b=", b, id(b))
  print("print_global3: c=", c, id(c))
  print("print_global3: d=", d, id(d))

print("a=", a, id(a))
print("b=", b, id(b))
print("c=", c, id(c))
print("c=", d, id(c))
print("")
print_global1()
print("")
print_global2()
print("")
print_global3()

The outputs are:

a= [1, 2, 3] 3206482320648
b= True 1625616544
c= 123 1626110848
c= Hello 1626110848

print_global1: a= [1, 2, 3] 3206482320648
print_global1: b= True 1625616544
print_global1: c= 123 1626110848
print_global1: d= Hello 3206481522616

print_global2: a= [1, 2, 3] 3206482320648
print_global2: b= True 1625616544
print_global2: c= 123 1626110848
print_global2: d= Hello 3206481522616

print_global3: a= [1, 2, 3, 4] 3206482320648
print_global3: b= False 1625616576
print_global3: c= 124 1626110880
print_global3: d= HELLO 3206482331664

Upvotes: 0

MAP
MAP

Reputation: 407

It's because Python uses static scope/is statically scoped. At implementation level Python has what is called a Symbol Table which has entries for things you define in code like variables and functions.

Each of those things are represented by a lexeme and have attributes like "value" and "scope".

For example for the first found, you have:

LEXEME |  VALUE | SCOPE

found  |  False |  outer

When you defined a second found, an entry was generated for that found with a scope "inner". So at the moment of execution of print("inner func ids:", id(arr), id(found)) Python searched the Symbol Table for an entry of "found" and used the most recent one (the one with the inner scope). Like this:

LEXEME |  VALUE | SCOPE

found  |  False |  outer
found  |  True  |  inner

The array is just unique, so when searching for that arr you again get the last entry for that lexeme or symbol and get the value of the unique outer array.

It's not about mutable or immutable but rather about scope.

Upvotes: 0

Julien
Julien

Reputation: 15071

Because redefining found in inner makes it local. Nothing to do with mutable or not.

Upvotes: 1

Related Questions