04Python 深拷贝浅拷贝 函数 递归 集合
Posted 虫虫研究室
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了04Python 深拷贝浅拷贝 函数 递归 集合相关的知识,希望对你有一定的参考价值。
1 深拷贝浅拷贝
1.1 a==b与a is b的区别
- a == b 比较两个对象的内容是否相等(可以是不同内存空间)
- a is b 比较a与b是否指向同一个内存地址,也就是a与b的id是否相同
1 >>> a = 1 2 >>> b = 1 3 >>> a == b 4 True 5 >>> a is b 6 True 7 >>> a = 257 8 >>> b = 257 9 >>> a is b 10 False
出于对性能的考虑,Python内部做了很多的优化工作,对于整数对象,Python把一些频繁使用的整数对象缓存起来,保存到一个叫small_ints的链表中,在Python的整个生命周期内,任何需要引用这些整数对象的地方,都不再重新创建新的对象,而是直接引用缓存中的对象。Python把这些可能频繁使用的整数对象规定在范围[-5, 256]之间的小对象放在small_ints中,但凡是需要用些小整数时,就从这里面取,不再去临时创建新的对象。因为257不再小整数范围内,因此尽管a和b的值是一样,但是他们在Python内部却是以两个独立的对象存在的,各自为政,互不干扰。
1 >>> c = 257 2 >>> def foo(): 3 ... a = 257 4 ... b = 257 5 ... print a is b 6 ... print a is c 7 ... 8 >>> foo() 9 True 10 False
Python程序由代码块构成,代码块作为程序的一个最小基本单位来执行。一个模块文件、一个函数体、一个类、交互式命令中的单行代码都叫做一个代码块。在上面这段代码中,由两个代码块构成,c = 257作为一个代码块,函数foo作为另外一个代码块。Python内部为了将性能进一步的提高,凡是在一个代码块中创建的整数对象,如果存在一个值与其相同的对象于该代码块中了,那么就直接引用,否则创建一个新的对象出来。Python出于对性能的考虑,但凡是不可变对象,在同一个代码块中的对象,只有是值相同的对象,就不会重复创建,而是直接引用已经存在的对象。因此,不仅是整数对象,还有字符串对象也遵循同样的原则。所以 a is b就理所当然的返回True了,而c和a不在同一个代码块中,因此在Python内部创建了两个值都是257的对象。
- l2 = l1,相当于l2也指向与l1的内存地址,修改l1的值,l2也会跟着改变
1 l1 = [1,1,1,1,2,3,4,5] 2 l2 = l1 #浅拷贝, l1和l2指向同一个内存地址 3 print(id(l1)) #查看内存地址 4 print(id(l2)) 5 for i in l2: 6 if i%2!=0: 7 l1.remove(i) #删除奇数 8 print(l1) #循环删list的时候,会导致下标错位,结果是不对的
运行结果如下:
42001160
42001160
[1, 1, 2, 4]
1.2 浅拷贝
import copy
l1 = [1,1,1,1,2,3,4,5]
l2 = l1 #浅拷贝, l和l2实际指向同一个内存地址
l3 = l1.copy() #浅拷贝
print(id(l1), id(l2), id(l3))
ll1 = [[1,2,3],[4,5,6]]
ll2 = ll1 #浅拷贝, l和l2实际指向同一个内存地址
ll3 = ll1.copy() #浅拷贝
print(id(ll1), id(ll2), id(ll3))
运行结果如下:
36164360 36164360 36164552
36165704 36165704 36165640
- 解析
1、b = a: 赋值引用,a 和 b 都指向同一个对象
2、b = a.copy(): 浅拷贝, a 和 b 是一个独立的对象,但他们的子对象还是指向统一对象(是引用)。
1 import copy 2 a = [1, 2, 3] 3 b = [4, 5, 6] 4 c = [a, b] 5 d = copy.copy(c) 6 print(id(c)) 7 print(id(d))
42500296 42500232
1 import copy 2 a = [1, 2, 3] 3 b = [4, 5, 6] 4 c = (a, b) 5 d = copy.copy(c) 6 print(id(c)) 7 print(id(d))
35510088 35510088
- 浅拷贝可变类型(比如列表),第一层的列表也会拷贝
- 浅拷贝不可变类型(比如元祖),d指向c的内存地址
1.3 深拷贝
1 import copy 2 l = [1,1,1,2,3,4,5] 3 l2 = copy.deepcopy(l)# 深拷贝
- 解析
b = copy.deepcopy(a): 深度拷贝, a 和 b 完全拷贝了父对象及其子对象,两者是完全独立的。
2 函数
2.1 函数定义
1 def db_connect(ip,port=3306): #1.位置参数,必填;2.默认值参数 2 print(ip,port) #函数体
1 def my3(): 2 a = 1 3 b = 2 4 c = 3 5 return a,b,c 6 7 b,c,d = my3() 8 s = my3() 9 print(b,c,d) 10 print(s)
运行结果:
1 2 3
(1, 2, 3)
2.2 return作用
1、结束函数,只要函数里面遇到return,函数立即结束运行
2、返回函数处理的结果
- 例:判断一个字符串是否是小数(含正小数和负小数)
1 def check_float(s): 2 \'\'\' 3 这个函数的作用就是判断传入的字符串是否是合法的小数 4 :param s: 传入一个字符串 5 :return: True/false 6 \'\'\' 7 s = str(s) 8 if s.count(\'.\')==1: 9 s_split = s.split(\'.\') 10 left,right = s_split 11 if left.isdigit() and right.isdigit(): 12 return True 13 elif left.startswith(\'-\') and left[1:].isdigit() \\ 14 and right.isdigit(): 15 return True 16 return False #上面的几个条件未满足,则会走到这一步 17 18 print(check_float(1.3)) 19 print(check_float(-1.3)) 20 print(check_float(\'01.3\')) 21 print(check_float(\'-1.3\')) 22 print(check_float(\'-a.3\')) 23 print(check_float(\'a.3\')) 24 print(check_float(\'1.3a3\')) 25 print(check_float(\'---.3a3\'))
2.3 可变参数
1 def send_sms(*args): #可变参数,参数组 2 #1、不是必传的 3 #2、它把传入的元素全部都放到了一个元组里面 4 #3、不限制参数个数 5 #4、它用在参数比较多的情况下 6 for p in args: 7 print(p) 8 9 send_sms() 10 print(\'-----------------------------\') 11 send_sms(1861231231) 12 print(\'-----------------------------\') 13 send_sms(1861231231,1232342,42342342)
运行结果:
-----------------------------
1861231231
-----------------------------
1861231231
1232342
42342342
- 有时候我们传入一个列表,本意是希望将列表中的所有元素都当做参数传递进去,这里直接将[\'a\', \'b\', \'c\']看做一个整体了,怎么办?
- 其实只需要在调用时前面加一个*号,就能实现将列表中的每个元素传递进去了。
- 其实不光列表,任何序列类型数据对象,比如字符串、元组都可以通过这种方式将内部元素逐一作为参数,传递给函数。
- 而字典,则会将所有的key逐一传递进去。
2.4 关键字参数
1 def send_sms2(**kwargs): 2 #1、不是必传的 3 #2、不限制参数个数 4 print(kwargs) 5 6 send_sms2() 7 send_sms2(name=\'xiaohei\',sex=\'nan\') 8 send_sms2(addr=\'北京\',country=\'中国\',c=\'abc\',f=\'kkk\')
运行结果:
{}
{\'name\': \'xiaohei\', \'sex\': \'nan\'}
{\'addr\': \'北京\', \'country\': \'中国\', \'c\': \'abc\', \'f\': \'kkk\'}
2.5 参数顺序
1 def my(name,country=\'China\',*args,**kwargs): 2 #1、位置参数 2、默认值参数 3、可变参数 4、关键字 3 print(name) 4 print(country) 5 print(args) 6 print(kwargs) 7 my(\'xiaojun\',\'Japan\',\'beijing\',\'天通苑\',color=\'红色\', 8 age=32)
运行结果:
xiaojun
Japan
(\'beijing\', \'天通苑\')
{\'color\': \'红色\', \'age\': 32}
2.6 全局变量
1 name = \'wangcan\'#全局变量 2 names = [] 3 def get_name(): 4 names.append(\'hahaha\') 5 name = \'hailong\' 6 print(\'1、函数里面的name\',name) 7 8 def get_name2(): 9 global name #声明name是全局变量 10 print(\'2、get_name2\',name) 11 12 get_name2() 13 get_name() 14 print(names) 15 print(\'3、函数外面的name\',name)
#运行结果: 2、get_name2 wangcan 1、函数里面的name hailong [\'hahaha\'] 3、函数外面的name wangcan
1 name = \'wangcan\'#全局变量 2 def get_name3(): 3 name = \'我是谁\' #不会对全局变量产生作用 4 print(name) 5 get_name3() 6 print(name)
#运行结果: 我是谁 wangcan
2.7 函数调用
1 def db_connect(ip, user, password, db, port): 2 print(ip) 3 print(user) 4 print(password) 5 print(db) 6 print(port) 7 8 db_connect(user = \'abc\', port= 3306, db = 1, ip = \'234234\', password = \'123456\') #记不住顺序可以这样调用 9 db_connect(\'192\',\'root\', db = 2, password = \'234\', port = 45)#这样也行, 混搭, 但\'192\',\'root\'必须按顺序写在前面
3 递归
函数自己调用自己
递归最多999次
效率没有循环高
1 #阶乘 1 × 2 × 3 × ... × n 2 def fact(n): 3 if n==1: 4 return 1 5 return n * fact(n - 1)
4 集合
1、天生可以去重
2、集合是无序
- 集合定义
1 jihe = set()
- 集合例子
1 l=[1,1,2,2,3,3] 2 res = set(l) 3 print(res)
#运行结果:集合 {1, 2, 3}
4.1 交集、并集、差集、对称差集
1 xingneng =[\'tanailing\',\'杨帆\',\'liurongxin\',\'小黑\'] 2 zdh = [\'tanailing\',\'杨帆\',\'liurongxin\',\'小军\',\'海龙\'] 3 xingneng = set(xingneng) 4 zdh = set(zdh) 5 #取交集 6 res1 = xingneng.intersection(zdh)#取交集 7 res2 = xingneng & zdh #取交集 8 #取并集 9 res3 = xingneng.union(zdh) #取并集,把2个集合合并到一起,然后去重 10 res4 = xingneng | zdh 11 #取差集 12 res5 = xingneng.difference(zdh) #取差集,在a里面有,在b里面没有的 13 res6 = xingneng - zdh #取差集 14 #取对称差集 15 res7 =xingneng.symmetric_difference(zdh)#两个里不重复的值 16 res8 = xingneng ^ zdh 17 18 print(res1) 19 print(res2) 20 print(res3) 21 print(res4) 22 print(res5) 23 print(res6) 24 print(res7) 25 print(res8)
#运行结果 {\'liurongxin\', \'杨帆\', \'tanailing\'} {\'liurongxin\', \'杨帆\', \'tanailing\'} {\'tanailing\', \'liurongxin\', \'小军\', \'海龙\', \'杨帆\', \'小黑\'} {\'tanailing\', \'liurongxin\', \'小军\', \'海龙\', \'杨帆\', \'小黑\'} {\'小黑\'} {\'小黑\'} {\'海龙\', \'小军\', \'小黑\'} {\'海龙\', \'小军\', \'小黑\'}
4.2 其他方法
1 import string 2 l1 = set(string.ascii_lowercase) 3 l2 = {\'a\',\'b\',\'c\'} 4 print(l2.issubset(l1)) #子集 5 print(l1.issuperset(l2)) #父集 6 print(l1.isdisjoint(l2)) #有交集,返回False, 没有交集,返回True
#运行结果 True True False
1 l2 = {\'a\',\'b\',\'c\'} 2 l2.add(\'s\') #增 3 print(l2) 4 5 l2.remove(\'a\') #删 6 print(l2) 7 8 l2.pop()#随机删 9 print(l2)
#运行结果: {\'c\', \'a\', \'b\', \'s\'} {\'c\', \'b\', \'s\'} {\'b\', \'s\'}
以上是关于04Python 深拷贝浅拷贝 函数 递归 集合的主要内容,如果未能解决你的问题,请参考以下文章