Some objects can change value

All names that refer to the same object are affected by a mutation
Only objects of mutable types can change: lists & dictionaries

List

  • append(elem): Add elem to the end of the list. Return None.
  • extend(s): Add all elements of iterable s to the end of the list. Return None.
  • insert(i, elem): Insert elem at index i. If i is greater than or equal to the length of the list, then elem is inserted at the end. This does not replace any existing elements, but only adds the new element elem. Return None.
  • remove(elem): Remove the first occurrence of elem in list. Return None. Errors if elem is not in the list.
  • pop(i): Remove and return the element at index i.
  • pop(): Remove and return the last element. ^fxmjvk.md
suits = ['coin','string','myriad']
original_suits = suits
print(suits.pop()) # 'myriad'
suits.remove('string')
print(suits) # ['coin']
suits.append('cup')
suits.extend(['sword', 'club'])
print(suits) # ['coin', 'cup','sword', 'club']
suits[2] ='spade'
suits[0:2] = ['heart', 'diamond']
print(suits) # ['heart', 'diamond','spade', 'club']
print(original_suits) # ['heart', 'diamond','spade', 'club']
 
"""original_suits is changed with the change of suit."""

Dictionary

  • pop()

Mutation can happen in a function call

def mystery(s):
	s.pop()
	s.pop()
"""or,"""
def mystery(s):
	s[2: ] = []
 
 
four = [1, 2, 3, 4]
len(four) # 4
 
mystery(four)
len(four) # 2

I think just like c language, the argument input is the address.

mystery can take no argument.

def another_mystery():
	four.pop()
	four.pop()

Straightly call four of global frame.

Instance of Class

Mutation

  • As long as we never modify objects, a compound object is just the totality of its pieces
  • A rational number is just its numerator and denominator
  • This view is no longer valid in the presence of change
  • A compound data object has an “identity” in addition to the pieces of which it is composed
  • A list is still “the same” list even if we change its contents
  • Conversely, we could have two lists that happen to have same contents, but different.
>>> a = [10]  
>>> b = a  
>>> a == b  
True  
>>> a.append(20)  
>>> a == b  
>>> True  
>>> a  
[10, 20]  
>>> b  
[10, 20]
 
>>> a is b
True
>>> a = [10]  
>>> b = [10]  
>>> a == b  
True
>>> a is b
False
>>> b.append(20)  
>>> a  
[10]  
>>> b  
[10, 20]  
>>> a == b  
False

Because in the upper one, a and b point to the same object, while in lower one, they point to different object, only have the same content in the first.

By the way, 0 == False but 0 is not False.

The Reason

Identity is different from Equality.

Identity

<exp0> is <exp1>
evaluates to True if both <exp0> and <exp1> evaluate to the same object

Equality

<exp0> == <exp1>
evaluates to True if both <exp0> and <exp1> evaluate to equal values.

Mutable Default Arguments are Dangerous

It is a part of function, not generated by a call. So when calling many times, the change of it will remain and accumulate.

def f(s=[]):
	s.append(3)

Every time f is called, s will be bound to the same value.

ATTENTION:

the content of mutable values can be changed in a function, since it is the address be passed in.
But, if we re-bind the name to a new list in function, would not affect, the original list. And it will do nothing, out of the function, the name is still pointing to the original list.

Let’s have an example:

def sprout_leaves(t, leaves):
    if is_leaf(t):
        t.extend([tree(leaf) for leaf in leaves])
    else:
        for branch in branches(t):
            sprout_leaves(branch, leaves)
    return t

It works well, since list is mutable and we changed(using extend) it in the function, so the list will be changed, even though out of function.

def sprout_leaves(t, leaves):
    if is_leaf(t):
        t = tree(label(t), [tree(leaf) for leaf in leaves])
    else:
        for branch in branches(t):
            sprout_leaves(branch, leaves)
    return t

It does not work, since we actually created a new list and bind the name t to the new list. As the t is just a name, out of function, t still points to the original one which is not mutated.

All in all,

Differences between Rebinding and Mutation

  • Rebindingself = other or x = 5 , make a local variable name point a new object.

  • mutationself.rest = ...list.append(),change the attribute of object and visible outside.

“Names in Python are just labels pointing to objects; reassigning a name does not mutate the object.”

So self = ... do nothing outside but self.attr = ... does!