Python is call-by-assignment

If you pass a mutable object into a method, the method gets a reference to that same object and you can mutate it to your heart's delight, but if you rebind the reference in the method, the outer scope will know nothing about it, and after you're done, the outer reference will still point at the original object.

If you pass an immutable object to a method, you still can't rebind the outer reference, and you can't even mutate the object.

例如 def foo(bar): 這個 function 的參數傳遞,其實是在 foo 的 local namespace 裡幫傳進去的物件綁定了一個叫做 bar 的名字(所謂的 assignment);如果你在 foo 裡 re-assign 了一個新的物件給 bar,實際上是把 bar 這個名字綁定到那個新的物件。

  • mutable objects: list, dict, set 的行為同 call-by-reference
  • immutable objects: boolean, int, float, long, str, unicode, tuple 的行為同 call-by-value

不過如果你把一個 mutable 物件放進 immutable 物件裡,例如把 list 放進 tuple 裡,則修改了 list 之後,那個 tuple 裡的 list 也是會被修改。

a_list = [1, 2, 3]
a_tuple = (a_list, 'a', 'b', 'c')
a_list.append(4)

Assignment is the binding of a name to an object: name = 'Molly'.
Assignment between names doesn't create a new object, both names are simply bound to the same object: nickname = name.

name = 'Mollie'
name = 'Vinta'

所謂的 assign 這個動作,其實是幫 'Mollie' 這個字串取一個名字叫做 name,所以如果你又加上一句 name = 'Vinta',實際上是建立了一個新的物件(字串 'Vinta'),再把這個新字串綁定到 name 這個名字。

# if bar refers to a mutable object
def foo(bar):
    bar.append('new value')
    print(bar)
    # output: ['old value', 'new value']

answer_list = ['old value', ]
foo(answer_list)
print(answer_list)
# output: ['old value', 'new value']

# if bar refers to an immutable object
def foo(bar):
    bar = 'new value'
    print(bar)
    # output: 'new value'

answer_list = 'old value'
foo(answer_list)
print(answer_list)
# output: 'old value'

# if bar refers to a mutable object and re-assign it in foo
def foo(bar):
    bar = ['new value', ]
    print(bar)
    # output: ['new value', ]

answer_list = ['old value', ]
foo(answer_list)
print(answer_list)
# output: ['old value', ]

ref:
https://stackoverflow.com/questions/986006/how-do-i-pass-a-variable-by-reference
https://jeffknupp.com/blog/2012/11/13/is-python-callbyvalue-or-callbyreference-neither/
https://docs.python.org/3/faq/programming.html#how-do-i-write-a-function-with-output-parameters-call-by-reference

scope

只有 module、class、function 才有建立新的 scope,if、while、for 並不會建立新的 scope。

some_list = [
    {
        'id': 1,
        'is_change': False,
    },
    {
        'id': 2,
        'is_change': False,
    },
    {
        'id': 3,
        'is_change': False,
    },
    {
        'id': 4,
        'is_change': False,
    },
]

for item in some_list:
    item['is_change'] = True

some_list 的每個 item 都會被更新,因為是 mutable objects 的行為是 call-by-reference。所以你不需要這樣:

new_list = []
for item in some_list:
    item['is_change'] = True
    new_list.append(item)