PyTips 0x0c – Python 知之深浅
admin
2023-07-31 01:45:49
0

项目地址:https://git.io/pytips

Python 中的对象分为两种:可变对象(mutable)和不可变对象(immutable)。不可变对象包括int,float,long,str,tuple等,可变对象包括list,set,dict等。在 Python 中,赋值(assignment, =)的过程仅仅是:

  1. 创建一个(某个值的)对象;

  2. 将变量名指向(引用)这个对象。

这就像 C 语言中指针的概念,只不过更灵活地是 Python 中的变量随时可以指向其它对象(不分类型),其它变量也可以指向这一对象。如果这一对象是可变的,那么对其中一个引用变量的改变会影响其它变量:

lst = [1, 2, 3]
s = lst
s.pop()
print(lst)

d = {\'a\': 0}
e = d
e[\'b\'] = 1
print(d)
[1, 2]
{\'b\': 1, \'a\': 0}

如果你不是刻意想要这样做(实际也很少会要这样操作),那么就可能导致一些意想不到的错误(尤其是在传递参数给函数的时候)。为了解决这一麻烦,最简单的方法就是不直接变量指向现有的对象,而是生成一份新的 copy 赋值给新的变量,有很多种语法可以实现:

lst = [1,2,3]

llst = [lst,
        lst[:],
        lst.copy(),
        [*lst]] # invalid in 2.7
for i, v in enumerate(llst):
    v.append(\"#{}\".format(i))
print(lst)

d = {\"a\": 0}
dd = [d,
      d.copy(),
      {**d}] # invalid in 2.7
for i, v in enumerate(dd):
    v[\'dd\'] = \"#{}\".format(i)
print(d)
[1, 2, 3, \'#0\']
{\'dd\': \'#0\', \'a\': 0}

deep vs shallow

上面给出的这些 copy 的例子比较简单,都没有嵌套的情况出现,如果这里的可变对象中还包含其它可变对象,结果会怎样呢:

lst = [0, 1, [2, 3]]

llst = [lst,
        lst[:],
        lst.copy(),
        [*lst]]
for i, v in enumerate(llst):
    v[2].append(\"#{}\".format(i))
print(lst)

d = {\"a\": {\"b\": [0]}}
dd = [d,
      d.copy(),
      {**d}]
for i, v in enumerate(dd):
    v[\'a\'][\'b\'].append(\"#{}\".format(i))
print(d)
[0, 1, [2, 3, \'#0\', \'#1\', \'#2\', \'#3\']]
{\'a\': {\'b\': [0, \'#0\', \'#1\', \'#2\']}}

这些 copy 的方法称为浅拷贝(shallow copy),它相比直接赋值更进了一步生成了新的对象,但是对于嵌套的对象仍然采用了赋值的方法来创建;如果要再进一步,则需要深拷贝(deep copy),由标准库 copy 提供:

from copy import deepcopy

lst = [0, 1, [2, 3]]
lst2 = deepcopy(lst)
lst2[2].append(4)
print(lst2)
print(lst)

d = {\"a\": {\"b\": [0]}}
d2 = deepcopy(d)
d2[\"a\"][\"b\"].append(1)
print(d2)
print(d)
[0, 1, [2, 3, 4]]
[0, 1, [2, 3]]
{\'a\': {\'b\': [0, 1]}}
{\'a\': {\'b\': [0]}}

清楚了赋值(引用)、copy 还是 deepcopy 之间的区别才能更好地避免意想不到的错误,同样也可以利用它们的特性去实现一些 little tricks,例如我们在 0x04 闭包与作用域 中利用可变对象的特性实现 nonlocal 的功能。关于可变对象的引用、传递等既是 Python 的基本属性,同时又因为隐藏在背后的“暗箱操作”而容易引起误解,想要深入了解可以进一步阅读参考链接的文章,我也会在后面的文章中继续一边学习、一边补充更多这方面的知识。


欢迎关注公众号 PyHub!

参考

  1. python基础(5):深入理解 python 中的赋值、引用、拷贝、作用域

相关内容

热门资讯

Mobi、epub格式电子书如... 在wps里全局设置里有一个文件关联,打开,勾选电子书文件选项就可以了。
定时清理删除C:\Progra... C:\Program Files (x86)下面很多scoped_dir开头的文件夹 写个批处理 定...
scoped_dir32_70... 一台虚拟机C盘总是莫名奇妙的空间用完,导致很多软件没法再运行。经过仔细检查发现是C:\Program...
500 行 Python 代码... 语法分析器描述了一个句子的语法结构,用来帮助其他的应用进行推理。自然语言引入了很多意外的歧义,以我们...
小程序支付时提示:appid和... [Q]小程序支付时提示:appid和mch_id不匹配 [A]小程序和微信支付没有进行关联,访问“小...
pycparser 是一个用... `pycparser` 是一个用 Python 编写的 C 语言解析器。它可以用来解析 C 代码并构...
微信小程序使用slider实现... 众所周知哈,微信小程序里面的音频播放是没有进度条的,但最近有个项目呢,客户要求音频要有进度条控制,所...
65536是2的几次方 计算2... 65536是2的16次方:65536=2⁶ 65536是256的2次方:65536=256 6553...
Apache Doris 2.... 亲爱的社区小伙伴们,我们很高兴地向大家宣布,Apache Doris 2.0.0 版本已于...
项目管理和工程管理的区别 项目管理 项目管理,顾名思义就是专注于开发和完成项目的管理,以实现目标并满足成功标准和项目要求。 工...