python里clear和copy_Python基础【3】:Python中的深浅拷贝解析

深浅拷贝

在研究Python的深浅拷贝区别前需要先弄清楚以下的一些基础概念:

变量--引用--对象(可变对象,不可变对象)

切片(序列化对象)--拷贝(深拷贝,浅拷贝)

我是铺垫~

一、【变量--引用--对象】:

Python中一切皆对象,甚至连type本身都是type对象。

1 >>> type(type(n1))

2

Python中的变量不同于与Java/c/c++不同,它是对象的引用,是动态型变量,数据类型无须提前声明,变量类型是根据对象的类型动态变化。

例如运行n=9,Python内部先在内存中找块地址来存储9,n只是对这个对象的引用,或者说将指针指向这个对象。

这里的整数对象9包含了两层含义:

1、数值为9

2、一个头部信息,告诉Python这是个int对象【可理解为一个指向int类型的指针】

cbe6345e9be2a74ad18ba9fe9ee0e3df.png

小结:

变量是一个系统表的元素,拥有指向对象的连接的空间;

对象是被分配的一块内存,用来存储值;

引用是在变量赋值时自动形成的变量到对象的指针。

再来看下面的例子:

1 >>> a = 3

2 >>> b = a

3 >>> id(a);id(b)

4 1627390480

5 1627390480

6 >>> del a

7 >>> b

8 3>>> a = 5>>> b30ce91281d4293b17376ad5bda7022ada.png96e2d7f17b8b56367a55e1c3c0144bec.png

可以看出,a和b共享引用,指向同一个内存地址(其id完全相同),所以将变量a删除或者将a赋值为4,都对变量b的数值无影响。

上面的例子有一个局限,就是数值类型对象是不可改变的,如果换成列表和元组对象呢?

二、【可变对象--不可变对象】

Python中的可变对象:可以修改的对象,列表和字典。

Python中的不可变对象:一旦创建就不可以修改的对象,字符串、元组、整数。1 >>> L1 = [2,3,4]

2 >>> L2 = L1

3 >>> L2

4 [2, 3, 4]

5 >>> L1= [5,6]

6 >>> L2

7 [2, 3, 4]

8 >>> L1 = [1,2,3]

9 >>> L2 = L1

10 >>> L1[0] = 99

11 >>> L1;L2

12 [99, 2, 3]

13 [99, 2, 3]

14 #因为对象本身变了

如此一来,可变对象的变量共享引用就可能会有问题了(原本对源变量的修改,一不小心影响了其他的变量引用)。所以针对这种情景,才有了深浅copy。

那么如果不想改变上面L2的值有两种作法:切片和copy模块。

1 >>> L1

2 [99, 2, 3]

3 >>> L2 = L1[:]

4 >>> L1,L2

5 ([99, 2, 3], [99, 2, 3])

6 >>> id(L1);id(L2)

7 3089554433480

8 3089554433992

9 >>> L1[0] = 100

10 >>> L1;L2

11 [100, 2, 3]

12 [99, 2, 3]

拷贝

切片技术的应用范围:序列对象,即列表、字符串、元组。注:序列是一类基本数据类型(字符串/列表/元组)的统称,这些数据类型都含有一些共同的特性。

切片不能应用于字典,对于字典只有dic.copy()方法和dic.deepcopy()方法。

1 >>> dic = {'name':'bolen','age':18}

2 >>> [item for item in dir(dic) if not item.startswith('__')]

3 ['clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']

4

5 #上面的语法和三元运算一样,x = 1 if n >2 else 3(或x = [2,1][n>2]),都是Python中的语法糖。1 >>> import copy

2 >>> L3 = copy.copy(L1)

3 >>> L4 = copy.deepcopy(L1)

4 >>>

上面铺垫了这么多,就是想说深浅拷贝,既可应用于序列对象也可用于字典。

【浅拷贝】

浅拷贝只拷贝顶层对象或者说父级对象。

【深拷贝】

深拷贝是拷贝所有对象,包括顶级对象和镶套对象,或者说拷贝所有父对象和子对象。

闲言少叙,show code:

1 >>> n1

2 {'k1': 'lilei', 'k3': ['yy', 456], 'k2': 123}

3 >>> n4 = n1

4 >>> n2= copy.copy(n1)

5 >>> n3 = copy.deepcopy(n1)

6 >>> n1;n2;n3;n4

7 {'k1': 'bboo', 'k3': ['yy', 456], 'k2': 123}

8 {'k1': 'bboo', 'k3': ['yy', 456], 'k2': 123}

9 {'k1': 'bboo', 'k3': ['yy', 456], 'k2': 123}

10 {'k1': 'bboo', 'k3': ['yy', 456], 'k2': 123}

11 >>> id(n1);id(n2);id(n3);id(n4)

12 3089553992072

13 3089554432904

14 3089554359368

15 3089553992072

16 #深浅拷贝内存地址和源对象都不一样。

17 >>> n1['k1'] = 'bolen'

18 >>> n1;n2;n3;n4

19 {'k1': 'bolen', 'k3': ['yy', 456], 'k2': 123}

20 {'k1': 'bboo', 'k3': ['yy', 456], 'k2': 123}

21 {'k1': 'bboo', 'k3': ['yy', 456], 'k2': 123}

22 {'k1': 'bolen', 'k3': ['yy', 456], 'k2': 123}

23 >>> n1['k3'][1]=789

24 >>> n1;n2;n3;n4

25 {'k1': 'bolen', 'k3': ['yy', 789], 'k2': 123}

26 {'k1': 'bboo', 'k3': ['yy', 789], 'k2': 123}

27 {'k1': 'bboo', 'k3': ['yy', 456], 'k2': 123}

28 {'k1': 'bolen', 'k3': ['yy', 789], 'k2': 123}

29 #当有多层镶套时,源对象改变后,浅拷贝和共享引用的值都变了,而深拷贝没有变。

58f5aeb62f96caa3adc362c497d46e98.png

【总结】

深浅拷贝都是对源对象的复制,占用不同的内存空间

如果源对象只有一级目录的话,源做任何改动,不影响深浅拷贝对象

如果源对象不止一级目录的话,源做任何改动,都要影响浅拷贝,但不影响深拷贝

序列对象的切片其实是浅拷贝,即只拷贝顶级的对象

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
推箱子游戏是一种经典的益智游戏,可以帮助玩家培养逻辑思维和动手能力。下面是Python实现推箱子游戏的代码及详细讲解。 代码如下: ```python # -*- coding:utf-8 -*- import os import copy MAP = [ "##########", "# #", "# OO #", "# OO #", "# #", "# OO #", "# OO #", "# #", "# OO #", "##########", ] PLAYER = "O" BOX = "X" TARGET = "T" WALL = "#" SPACE = " " def clear(): os.system("cls" if os.name == "nt" else "clear") def is_win(map): for line in map: if BOX in line: return False return True def get_pos(map, char): for i, line in enumerate(map): if char in line: return i, line.index(char) def move(map, p, q, x, y): if map[x][y] == WALL: return False if map[x][y] == BOX: if map[x+p][y+q] in [WALL, BOX]: return False map[x+p] = map[x+p][:y+q] + BOX + map[x+p][y+q+1:] map[x] = map[x][:y] + SPACE + map[x][y+1:] map[x+p] = map[x+p][:y+q] + PLAYER + map[x+p][y+q+1:] return True def show_map(map): for line in map: print(line) def main(): map = copy.deepcopy(MAP) while True: clear() show_map(map) if is_win(map): print("恭喜你赢了!") break p, q = 0, 0 move_dir = input("请输入移动方向(w/s/a/d):") if move_dir == "w": p, q = -1, 0 elif move_dir == "s": p, q = 1, 0 elif move_dir == "a": p, q = 0, -1 elif move_dir == "d": p, q = 0, 1 else: continue x, y = get_pos(map, PLAYER) if move(map, p, q, x, y): continue if move(map, p, q, x+p, y+q): continue if __name__ == "__main__": main() ``` 代码解析: 首先定义了游戏地图,其包含了玩家、箱子、目标、墙和空地等元素。其,玩家用字母“O”表示,箱子用字母“X”表示,目标用字母“T”表示,墙用井号“#”表示,空地用空格符号表示。 定义了一些常量,如玩家、箱子、目标、墙和空地等元素的表示符号。 定义了一些函数,如清屏函数、判断是否胜利函数、获取元素位置函数、移动函数和显示地图函数等。 在主函数,首先将地图备份一份,然后进入游戏循环。在每个循环,首先清屏并显示地图,在判断是否胜利后,提示玩家输入移动方向。如果输入的是无效方向,则重新输入。如果输入的是有效方向,则获取玩家当前位置,并尝试移动。如果移动成功,则重新显示地图。如果移动失败,则继续等待玩家输入。 最后,程序结束。 这是一个简单的推箱子游戏,虽然代码量不多,但是涉及到了很多基础知识,如列表操作、字符串操作、条件判断和循环等。希望这个例子能够帮助读者更好地理解Python基础语法和应用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值