首页 文章资讯内容详情

关于Python中的引用

2026-06-01 4 花语

本文内容纲要:

作为一个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], 2AdaKing-Milbanke:[RalphKing-Milbanke,FannyHeriot], 3RalphKing-Milbanke:[AugustaAdaKing,WilliamKing-Noel], 4AnneIsabellaBlunt:[AugustaAdaKing,WilliamKing-Noel], 5ByronKing-Noel:[AugustaAdaKing,WilliamKing-Noel], 6AugustaAdaKing:[AnneIsabellaMilbanke,GeorgeGordonByron], 7GeorgeGordonByron:[CatherineGordon,CaptainJohnByron], 8JohnByron:[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