# 对象变动 Mutation
# 对象变动(Mutation)
Python中可变(**mutable**)与不可变(**immutable**)的数据类型让新手很是头痛。简单的说,可变(mutable)意味着"可以被改动",而不可变(immutable)的意思是“常量(constant)”。想把脑筋转动起来吗?考虑下这个例子:
~~~
foo = ['hi']
print(foo)
# Output: ['hi']
bar = foo
bar += ['bye']
print(foo)
# Output: ['hi', 'bye']
~~~
刚刚发生了什么?我们预期的不是那样!我们期望看到是这样的:
~~~
foo = ['hi']
print(foo)
# Output: ['hi']
bar = foo
bar += ['bye']
print(foo)
# Output: ['hi']
print(bar)
# Output: ['hi', 'bye']
~~~
这不是一个bug。这是对象可变性(**mutability**)在作怪。每当你将一个变量赋值为另一个可变类型的变量时,对这个数据的任意改动会同时反映到这两个变量上去。新变量只不过是老变量的一个别名而已。这个情况只是针对可变数据类型。下面的函数和可变数据类型让你一下就明白了:
~~~
def add_to(num, target=[]):
target.append(num)
return target
add_to(1)
# Output: [1]
add_to(2)
# Output: [1, 2]
add_to(3)
# Output: [1, 2, 3]
~~~
你可能预期它表现的不是这样子。你可能希望,当你调用`add_to`时,有一个新的列表被创建,就像这样:
~~~
def add_to(num, target=[]):
target.append(num)
return target
add_to(1)
# Output: [1]
add_to(2)
# Output: [2]
add_to(3)
# Output: [3]
~~~
啊哈!这次又没有达到预期,是列表的可变性在作怪。在Python中当函数被定义时,默认参数只会运算一次,而不是每次被调用时都会重新运算。你应该永远不要定义可变类型的默认参数,除非你知道你正在做什么。你应该像这样做:
~~~
def add_to(element, target=None):
if target is None:
target = []
target.append(element)
return target
~~~
现在每当你在调用这个函数不传入`target`参数的时候,一个新的列表会被创建。举个例子:
~~~
add_to(42)
# Output: [42]
add_to(42)
# Output: [42]
add_to(42)
# Output: [42]
~~~
- 简介
- 序
- 译后感
- 原作者前言
- *args 和 **kwargs
- *args 的用法
- **kwargs 的用法
- 使用 *args 和 **kwargs 来调用函数
- 啥时候使用它们
- 调试 Debugging
- 生成器 Generators
- 可迭代对象(Iterable)
- 迭代器(Iterator)
- 迭代(Iteration)
- 生成器(Generators)
- Map和Filter
- Map
- Filter
- set 数据结构
- 三元运算符
- 装饰器
- 一切皆对象
- 在函数中定义函数
- 从函数中返回函数
- 将函数作为参数传给另一个函数
- 你的第一个装饰器
- 使用场景
- 授权
- 日志
- 带参数的装饰器
- 在函数中嵌入装饰器
- 装饰器类
- Global和Return
- 多个return值
- 对象变动 Mutation
- slots魔法
- 虚拟环境
- 容器 Collections
- 枚举 Enumerate
- 对象自省
- dir
- type和id
- inspect模块
- 推导式 Comprehension
- 列表推导式
- 字典推导式
- 集合推导式
- 异常
- 处理多个异常
- finally从句
- try/else从句
- lambda表达式
- 一行式
- For - Else
- else语句
- open函数
- 目标Python2+3
- 协程
- 函数缓存
- Python 3.2+
- Python 2+
- 上下文管理器
- 基于类的实现
- 处理异常
- 基于生成器的实现