关于Python中的引用
本文内容纲要:
作为一个python初学者,今天被一个python列表和词典引用的问题折磨了很久,但其实了解了缘由也很简单,记录在此备忘。
首先背书python中的引用对象问题:
1.python不允许程序员选择采用传值还是传引用。Python参数传递采用的肯定是“传对象引用”的方式。实际上,这种方式相当于传值和传引用的一种综合。如果函数收到的是一个可变对象(比如字典或者列表)的引用,就能修改对象的原始值——相当于通过“传引用”来传递对象。如果函数收到的是一个不可变对象(比如数字、字符或者元组)的引用,就不能直接修改原始对象——相当于通过“传值'来传递对象。
2.当人们复制列表或字典时,就复制了对象列表的引用同,如果改变引用的值,则修改了原始的参数。
3.为了简化内存管理,Python通过引用计数机制实现自动垃圾回收功能,Python中的每个对象都有一个引用计数,用来计数该对象在不同场所分别被引用了多少次。每当引用一次Python对象,相应的引用计数就增1,每当消毁一次Python对象,则相应的引用就减1,只有当引用计数为零时,才真正从内存中删除Python对象。
列表引用
首先看2个示例:
1defadd_list(p):
2p=p+[1]
3p1=[1,2,3]
4add_list(p1)
5printp1
6>>>[1,2,3]
7
8defadd_list(p):
9p+=[1]
10p2=[1,2,3]
11proc2(p2)
12printp2
13>>>[1,2,3,1]
这主要是由于“=”操作符会新建一个新的变量保存赋值结果,然后再把引用名指向“=”左边,即修改了原来的p引用,使p成为指向新赋值变量的引用。而+=不会,直接修改了原来p引用的内容,事实上+=和=在python内部使用了不同的实现函数。
词典引用
1a=[]
2b={'num':0,'sqrt':0}
3resurse=[1,2,3]
4foriinresurse:
5b['num']=i
6b['sqrt']=i*i
7a.append(b)
8printa
9>>>[{'num':3,'sqrt':9},{'num':3,'sqrt':9},{'num':3,'sqrt':9}]
但我们实际想要的结果是这样的:
[{'num':1,'sqrt':1},{'num':2,'sqrt':4},{'num':3,'sqrt':9}]
这是由于a中的元素就是b的引用。可以修改为:
1a=[]
2resurse=[1,2,3]
3foriinresurse:
4a.append({"num":i,"sqrt":i*i})
实例
接下来可以看看折磨我半天的一个实例:
定义一个家族谱词典:value为key的parent.要写一个函数,输入人名,给出这个人的所有祖先名字。
开始的做法:
1ada_family={'JudithBlunt-Lytton':['AnneIsabellaBlunt','WilfridScawenBlunt'],
2'AdaKing-Milbanke':['RalphKing-Milbanke','FannyHeriot'],
3'RalphKing-Milbanke':['AugustaAdaKing','WilliamKing-Noel'],
4'AnneIsabellaBlunt':['AugustaAdaKing','WilliamKing-Noel'],
5'ByronKing-Noel':['AugustaAdaKing','WilliamKing-Noel'],
6'AugustaAdaKing':['AnneIsabellaMilbanke','GeorgeGordonByron'],
7'GeorgeGordonByron':['CatherineGordon','CaptainJohnByron'],
8'JohnByron':['Vice-AdmiralJohnByron','SophiaTrevannion']}
9
10
11defancestors(genealogy,person):
12ifpersoningenealogy:
13parents=genealogy[person]
14result=parents
15forparentinparents:
16result+=ancestors(genealogy,parent)
17returnresult
18return[]
19printancestors2(ada_family,'JudithBlunt-Lytton')
20printada_family
21
22#>>>['AnneIsabellaBlunt','WilfridScawenBlunt','AugustaAdaKing',
23#'WilliamKing-Noel','AnneIsabellaMilbanke','GeorgeGordonByron',
24#'CatherineGordon','CaptainJohnByron','CatherineGordon',
25#'CaptainJohnByron','AnneIsabellaMilbanke','GeorgeGordonByron',
26#'CatherineGordon','CaptainJohnByron','CatherineGordon',
27#'CaptainJohnByron','CatherineGordon','CaptainJohnByron',
28#'CatherineGordon','CaptainJohnByron']
29#
30#>>>{'RalphKing-Milbanke':['AugustaAdaKing','WilliamKing-Noel'],
31#'AdaKing-Milbanke':['RalphKing-Milbanke','FannyHeriot'],
32#'AnneIsabellaBlunt':['AugustaAdaKing','WilliamKing-Noel','AnneIsabellaMilbanke','GeorgeGordonByron','CatherineGordon','CaptainJohnByron','CatherineGordon','CaptainJohnByron'],
33#'AugustaAdaKing':['AnneIsabellaMilbanke','GeorgeGordonByron','CatherineGordon','CaptainJohnByron','CatherineGordon','CaptainJohnByron'],
34#'JudithBlunt-Lytton':['AnneIsabellaBlunt','WilfridScawenBlunt','AugustaAdaKing','WilliamKing-Noel','AnneIsabellaMilbanke','GeorgeGordonByron','CatherineGordon','CaptainJohnByron','CatherineGordon','CaptainJohnByron','AnneIsabellaMilbanke','GeorgeGordonByron','CatherineGordon','CaptainJohnByron','CatherineGordon','CaptainJohnByron','CatherineGordon','CaptainJohnByron','CatherineGordon','CaptainJohnByron'],
35#'ByronKing-Noel':['AugustaAdaKing','WilliamKing-Noel'],
36#'GeorgeGordonByron':['CatherineGordon','CaptainJohnByron'],
37#'JohnByron':['Vice-AdmiralJohnByron','SophiaTrevannion']}
这并不是我想要的结果,开始检查了好久都不明所以,直到我突然想起来打印词典ada_family,才发现词典已经不是原来的值了,这时,我才反应过来是引用的原因。由于我们使用的result实际就是词典中的value列表的引用,改动了result,就也改动了ada_family词典,从而导致结果不正确(有很多重复项)。
修改为如下写法即可。
1defancestors(genealogy,person):
2ifpersoningenealogy:
3parents=genealogy[person]
4result=parents
5forparentinparents:
6result=result+ancestors2(genealogy,parent)
7returnresult
8return[]
9
10#>>>['AnneIsabellaBlunt','WilfridScawenBlunt','AugustaAdaKing',
11#'WilliamKing-Noel','AnneIsabellaMilbanke','GeorgeGordonByron',
12#'CatherineGordon','CaptainJohnByron']
13#
14#>>>{'RalphKing-Milbanke':['AugustaAdaKing','WilliamKing-Noel'],
15#'AdaKing-Milbanke':['RalphKing-Milbanke','FannyHeriot'],
16#'AnneIsabellaBlunt':['AugustaAdaKing','WilliamKing-Noel'],
17#'AugustaAdaKing':['AnneIsabellaMilbanke','GeorgeGordonByron'],
18#'JudithBlunt-Lytton':['AnneIsabellaBlunt','WilfridScawenBlunt'],
19#'ByronKing-Noel':['AugustaAdaKing','WilliamKing-Noel'],
20#'GeorgeGordonByron':['CatherineGordon','CaptainJohnByron'],
21#'JohnByron':['Vice-AdmiralJohnByron','SophiaTrevannion']}
此时就不会修改原词典内容,得到的也是正确结果。
当然,我们也可以简单的使用以下方法实现,就避免了引用带来的麻烦:
1defancestors(genealogy,person):
2ifpersoningenealogy:
3parents=genealogy[person]
4returnparents+ancestors(genealogy,parents[0])+ancestors(genealogy,parents[1])
5return[]
这里再备忘一些关于列表和词典的操作:
列表list[]
赋值list1[3:4]=[a,b]
len(list)长度
dellist删除对象
列表对象支持的方法:
append(x)尾部追加单个对象x,使用多个对象会引起异常。
count(x)返回对象x在list中出现的次数
extend(L)将列表L中的项添加到表中
index(x)返回匹配对象x第一个表项的索引,无匹配时产生异常
insert(i,x)在索引‘i’的元素钱插入对象x
pop(x)删除列表中索引x的表项,并返回同该表项的值,无参数删除最后
remove(x)删除表匹配对象x的第一个元素,无匹配时异常
reverse()颠倒列表元素的顺序
sort()对列表排序
此外可简单使用+实现列表连接:[3,4]+[[1,2],5,6]-->[3,4,[1,2],5,6]
删除列表中的重复项:M=list(set(L)),python的set和其他语言类似,是一个无序不重复元素集
词典dictionary{name:value,...}
+++字典的方法
has_keys(x)若字典中有x返回true
keys()返回键的列表
values()返回值的列表
dict.items()返回tuples的列表。每个tuple有字典的dict的键和相应的值组成
clear()删除词典的所有条目
copy()返回字典的高层结构的拷贝,但不复制嵌入结构,而复制那些结构的引用。
update(x)用字典x中的键/值对更新字典的内容。
get(x[,y])返回键x。若未找到返回None
内置对象类型转换
str(x)将对象x翻译为字符串
list(x)将对象序列x作为列表返回。例如‘hello’返回['h','e','l','l','o'],将tuple转换为列表
tuple(x)将对象序列x作为tuple返回
int(x)将字符串和数字转换为整数,对浮点进行舍位而非舍入
long(x)将字符串和数字转换为长整形
float(x)将str和num转换为浮点对象
complex(x,y)将x做实部,y做虚部创建复数
hex(x)将整数或长整数转换为十六进制字符串
oct(x)将整数或长整数转换为八进制字符串
ord(x)返回字符x的ASCII值
chr(x)返回ASCII码x代表的字符
min(x[,...])返回序列中最小的元素
max(x[,...])返回序列中最大的元素
参考
http://opengit.org/open/?f=python_note
http://blog.csdn.net/wayne92/article/details/1133465
http://hliang.sinaapp.com/?p=233
本文内容总结:
原文链接:https://www.cnblogs.com/yuyan/archive/2012/04/21/2461673.html