红魔咖啡馆

头发越掉越多,头发越掉越少

0%

【CS61A】CS61A——Mutablity

Mutablity

Objects

  • 对象用于表达信息,是一种包含了数据与行为的数据抽象
  • 有属性的东西都可以作为对象,python中一切皆对象
  • Python中,优先级最高的对象被称为类(class)
  • 面向对象编程(OOP):
    • 对象是OOP的核心
    • OOP使用一种暗喻来组织大型程序
    • 使用一种特殊语法可以提高程序的可读性与组织
  • 很多数据操作都是通过对象实现的
  • 对象可以做许多相关的事情,而函数只能做一件事

e.g. String

字符串是一种表达文本的数据抽象 ### 字符串的表示 目前常见的表示方法是用ASCII与Unicode字符集表示字符 前者包含了控制字符、数字、字母与标点,后者则包含了不同语言中的更多字符

1
2
3
4
from unicodedata import name, lookup
print(name('A')) # 查询字符集中的字符名称
print(lookup('BABY')) # 根据字符名称输出对应字符
print(lookup('BABY').encode()) # 查看该字符的字节编码
LATIN CAPITAL LETTER A
👶
b'\xf0\x9f\x91\xb6'

Mutation Operations

一些对象是可以改变的

1
2
3
4
5
6
7
8
9
10
11
suits = ['coin', 'string', 'myriad']
original_suits = suits
print(suits.pop()) # 弹出一个元素(默认最后一个)
suits.remove('string') # 移除指定元素
print(suits)
suits.append('cup') # 在尾部增加一个元素
suits.extend(['sword', 'club']) # 添加序列中的多个元素来拓展列表
print(suits)
suits[2] = 'spade'
suits[0:2] = ['heart', 'diamond']
print(original_suits)
myriad
['coin']
['coin', 'cup', 'sword', 'club']
['heart', 'diamond', 'spade', 'club']

根据以上代码发现,我们可以对一个对象(suits)进行若干操作来变化其值 而我们在最初将suits与original_suits进行绑定,故变化也会在original_suits中体现 综上,所有指向相同对象的names都会受到Mutation的影响,其中这里的mutation指对象发生的变化 只有可变类型的对象才能更改,如列表与字典

函数调用时发生的Mutation

函数可以更改其作用域中任何可变对象的值

1
2
3
4
5
def mystery(s):
    s.pop()
    s.pop()
four = [1,2,3,4]
mystery(four)

mystery函数实现了对列表对象值的更改,甚至mystery不需要传入参数,直接更改其所在作用域(全局作用域)中four列表的内容

表达式的Mutation

表达式的值会随着names绑定值或对象的改变而改变

1
2
3
4
x = [1,2]
print(x+x)
x.append(3)
print(x+x)
[1, 2, 1, 2]
[1, 2, 3, 1, 2, 3]

Tuples

  • 元组是一种不可变的序列,使用圆括号包裹起来
  • 实际上,任何以逗号隔开的元素都会被解释成元组,非必须加圆括号
  • 使用tuple()创建元组或将其他序列转化为元组
  • 在单个元素后加一个逗号可以将单个元素转化成元组
  • 元组可以相加,也可以使用成员运算符in来判断元素是否存在
  • 由于元组不可变,可以将其作为字典的键使用
  • 若元组中包含了可变对象,则该对象可以被更改
1
2
3
s = ([1,2],3)
s[0][0]=4
print(s)
([4, 2], 3)

Mutation

相同与改变

1
2
3
4
5
a = [10]
b = a
print(a==b)
a.append(20)
print(a==b)
True
True

在这个例子中,我们可以说a与b是相同的,因为b与a绑定到了同一个对象,当对其中一个发生变化,另一个也会同时改变

1
2
3
4
5
a = [10]
b = [10]
print(a==b)
b.append(20)
print(a==b)

在这个例子中,a与b是不同的,尽管它们曾有过相同的内容,但对b进行改变后,a会随之改变,因此这时二者便不同了

Identity Operators

Identity<exp0> is <exp1> 当两个表达式指向相同对象时返回True Equality <exp0> == <exp1> 当两个表达式拥有相同值时返回True

相同对象始终拥有相等的值,但反之不一定成立

1
2
3
4
5
a = [10]
b = [10]
c = b
print(a is b)
print(b is c)
False
True

可变对象在函数中的默认值

函数中声明的默认值是函数值的一部分,而不是每次调用时才生成 这导致了若该对象是可变的,而且在函数中间进行了修改,则该修改会在下次调用函数时保留 如下面的代码,每次调用增加的值会保留在默认值中

1
2
3
4
5
def f(s=[]):
    s.append(3)
    return len(s)
for i in range(3):
    print(f())
1
2
3

Mutable Fuctions

在函数中使用可变对象可以在多次调用时保留上次操作的值

1
2
3
4
5
6
7
8
9
10
11
12
13
def make_withdraw_list(balance):
    b = [balance]
    def withdraw(amount):
        if amount > b[0]:
            return 'Insufficient funds'
        b[0] = b[0] - amount
        return b[0]
    return withdraw

withdraw = make_withdraw_list(100)
print(withdraw(25))
print(withdraw(25))
withdraw(100)
75
50
'Insufficient funds'

该函数将存款存在作为可变对象的列表中 函数中的withdraw函数始终指向列表b并修改其值,该列表总是这个列表,随着时间其中的内容被更改 为了实现每次更改列表中的值,该函数使用了可变对象来创建了一个可变函数 function