python中的引用

作为一个python初学者,今天被一个python列表和词典引用的问题折磨了很久,但其实了解了缘由也很简单,记录在此备忘。

首先背书python中的引用对象问题:

1. python不允许程序员选择采用传值还是传引用。Python参数传递采用的肯定是“传对象引用”的方式。实际上,这种方式相当于传值和传引用的一种综合。如果函数收到的是一个可变对象(比如字典或者列表)的引用,就能修改对象的原始值——相当于通过“传引用”来传递对象。如果函数收到的是一个不可变对象(比如数字、字符或者元组)的引用,就不能直接修改原始对象——相当于通过“传值‘来传递对象。

2. 当人们复制列表或字典时,就复制了对象列表的引用同,如果改变引用的值,则修改了原始的参数。

3. 为了简化内存管理,Python通过引用计数机制实现自动垃圾回收功能,Python中的每个对象都有一个引用计数,用来计数该对象在不同场所分别被引用了多少次。每当引用一次Python对象,相应的引用计数就增1,每当消毁一次Python对象,则相应的引用就减1,只有当引用计数为零时,才真正从内存中删除Python对象。

 

列表引用

首先看2个示例:

[python] view plaincopy

  1. def add_list(p):
  2. p = p + [1]
  3. p1 = [1,2,3]
  4. add_list(p1)
  5. print p1
  6. >>> [1, 2, 3]
  7. def add_list(p):
  8. p += [1]
  9. p2 = [1,2,3]
  10. proc2(p2)
  11. print p2
  12. >>>[1, 2, 3, 1]

这主要是由于“=”操作符会新建一个新的变量保存赋值结果,然后再把引用名指向“=”左边,即修改了原来的p引用,使p成为指向新赋值变量的引用。而+=不会,直接修改了原来p引用的内容,事实上+=和=在python内部使用了不同的实现函数。

 

词典引用

[python] view plaincopy

  1. 1 a = []
  2. 2 b = {‘num‘:0, ‘sqrt‘:0}
  3. 3 resurse = [1,2,3]
  4. 4 for i in resurse:
  5. 5   b[‘num‘] = i
  6. 6   b[‘sqrt‘] = i * i
  7. 7   a.append(b)
  8. 8 print a
  9. 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的引用。可以修改为:

1 a = []
2 resurse = [1,2,3]
3 for i in resurse:
4   a.append({"num": i, "sqrt": i * i})

实例

接下来可以看看折磨我半天的一个实例:

定义一个家族谱词典:value为key的parent. 要写一个函数,输入人名,给出这个人的所有祖先名字。

开始的做法:

 1 ada_family = { ‘Judith Blunt-Lytton‘: [‘Anne Isabella Blunt‘, ‘Wilfrid Scawen Blunt‘],
 2               ‘Ada King-Milbanke‘: [‘Ralph King-Milbanke‘, ‘Fanny Heriot‘],
 3               ‘Ralph King-Milbanke‘: [‘Augusta Ada King‘, ‘William King-Noel‘],
 4               ‘Anne Isabella Blunt‘: [‘Augusta Ada King‘, ‘William King-Noel‘],
 5               ‘Byron King-Noel‘: [‘Augusta Ada King‘, ‘William King-Noel‘],
 6               ‘Augusta Ada King‘: [‘Anne Isabella Milbanke‘, ‘George Gordon Byron‘],
 7               ‘George Gordon Byron‘: [‘Catherine Gordon‘, ‘Captain John Byron‘],
 8               ‘John Byron‘: [‘Vice-Admiral John Byron‘, ‘Sophia Trevannion‘] }
 9
10
11 def ancestors(genealogy, person):
12     if person in genealogy:
13         parents = genealogy[person]
14         result = parents
15         for parent in parents:
16             result += ancestors(genealogy, parent)
17         return result
18     return []
19 print ancestors2(ada_family, ‘Judith Blunt-Lytton‘)
20 print ada_family
21
22 #>>> [‘Anne Isabella Blunt‘, ‘Wilfrid Scawen Blunt‘, ‘Augusta Ada King‘,
23 #    ‘William King-Noel‘, ‘Anne Isabella Milbanke‘, ‘George Gordon Byron‘,
24 #    ‘Catherine Gordon‘, ‘Captain John Byron‘, ‘Catherine Gordon‘,
25 #    ‘Captain John Byron‘, ‘Anne Isabella Milbanke‘, ‘George Gordon Byron‘,
26 #    ‘Catherine Gordon‘, ‘Captain John Byron‘, ‘Catherine Gordon‘,
27 #    ‘Captain John Byron‘, ‘Catherine Gordon‘, ‘Captain John Byron‘,
28 #    ‘Catherine Gordon‘, ‘Captain John Byron‘]
29 #
30 #>>> {‘Ralph King-Milbanke‘: [‘Augusta Ada King‘, ‘William King-Noel‘],
31 #    ‘Ada King-Milbanke‘: [‘Ralph King-Milbanke‘, ‘Fanny Heriot‘],
32 #    ‘Anne Isabella Blunt‘: [‘Augusta Ada King‘, ‘William King-Noel‘, ‘Anne Isabella Milbanke‘, ‘George Gordon Byron‘, ‘Catherine Gordon‘, ‘Captain John Byron‘, ‘Catherine Gordon‘, ‘Captain John Byron‘],
33 #    ‘Augusta Ada King‘: [‘Anne Isabella Milbanke‘, ‘George Gordon Byron‘, ‘Catherine Gordon‘, ‘Captain John Byron‘, ‘Catherine Gordon‘, ‘Captain John Byron‘],
34 #    ‘Judith Blunt-Lytton‘: [‘Anne Isabella Blunt‘, ‘Wilfrid Scawen Blunt‘, ‘Augusta Ada King‘, ‘William King-Noel‘, ‘Anne Isabella Milbanke‘, ‘George Gordon Byron‘, ‘Catherine Gordon‘, ‘Captain John Byron‘, ‘Catherine Gordon‘, ‘Captain John Byron‘, ‘Anne Isabella Milbanke‘, ‘George Gordon Byron‘, ‘Catherine Gordon‘, ‘Captain John Byron‘, ‘Catherine Gordon‘, ‘Captain John Byron‘, ‘Catherine Gordon‘, ‘Captain John Byron‘, ‘Catherine Gordon‘, ‘Captain John Byron‘],
35 #    ‘Byron King-Noel‘: [‘Augusta Ada King‘, ‘William King-Noel‘],
36 #    ‘George Gordon Byron‘: [‘Catherine Gordon‘, ‘Captain John Byron‘],
37 #    ‘John Byron‘: [‘Vice-Admiral John Byron‘, ‘Sophia Trevannion‘]}

这并不是我想要的结果,开始检查了好久都不明所以,直到我突然想起来打印词典ada_family,才发现词典已经不是原来的值了,这时,我才反应过来是引用的原因。由于我们使用的result实际就是词典中的value列表的引用,改动了result,就也改动了ada_family词典,从而导致结果不正确(有很多重复项)。

修改为如下写法即可。

 1 def ancestors(genealogy, person):
 2     if person in genealogy:
 3         parents = genealogy[person]
 4         result = parents
 5         for parent in parents:
 6             result = result + ancestors2(genealogy, parent)
 7         return result
 8     return []
 9
10 #>>> [‘Anne Isabella Blunt‘, ‘Wilfrid Scawen Blunt‘, ‘Augusta Ada King‘,
11 #    ‘William King-Noel‘, ‘Anne Isabella Milbanke‘, ‘George Gordon Byron‘,
12 #    ‘Catherine Gordon‘, ‘Captain John Byron‘]
13 #
14 #>>> {‘Ralph King-Milbanke‘: [‘Augusta Ada King‘, ‘William King-Noel‘],
15 #    ‘Ada King-Milbanke‘: [‘Ralph King-Milbanke‘, ‘Fanny Heriot‘],
16 #    ‘Anne Isabella Blunt‘: [‘Augusta Ada King‘, ‘William King-Noel‘],
17 #    ‘Augusta Ada King‘: [‘Anne Isabella Milbanke‘, ‘George Gordon Byron‘],
18 #    ‘Judith Blunt-Lytton‘: [‘Anne Isabella Blunt‘, ‘Wilfrid Scawen Blunt‘],
19 #    ‘Byron King-Noel‘: [‘Augusta Ada King‘, ‘William King-Noel‘],
20 #    ‘George Gordon Byron‘: [‘Catherine Gordon‘, ‘Captain John Byron‘],
21 #    ‘John Byron‘: [‘Vice-Admiral John Byron‘, ‘Sophia Trevannion‘]}

此时就不会修改原词典内容,得到的也是正确结果。

当然,我们也可以简单的使用以下方法实现,就避免了引用带来的麻烦:

1 def ancestors(genealogy, person):
2     if person in genealogy:
3         parents = genealogy[person]
4         return parents + ancestors(genealogy,parents[0]) + ancestors(genealogy,parents[1])
5     return []

这里再备忘一些关于列表和词典的操作:

列表  list[]

赋值 list1[3:4]=[a,b]

len(list)长度

del list 删除对象

列表对象支持的方法:

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[,...]) 返回序列中最大的元素

时间: 2024-12-18 16:04:17

python中的引用的相关文章

python中的引用传递,可变对象,不可变对象,list注意点

python中的引用传递 首先必须理解的是,python中一切的传递都是引用(地址),无论是赋值还是函数调用,不存在值传递. 可变对象和不可变对象 python变量保存的是对象的引用,这个引用指向堆内存里的对象,在堆中分配的对象分为两类,一类是可变对象,一类是不可变对象.不可变对象的内容不可改变,保证了数据的不可修改(安全,防止出错),同时可以使得在多线程读取的时候不需要加锁. 不可变对象(变量指向的内存的中的值不能够被改变) 当更改该对象时,由于所指向的内存中的值不可改变,所以会把原来的值复制

Python 中的引用和类属性的初步理解

最近对Python 的对象引用机制稍微研究了一下,留下笔记,以供查阅. 首先有一点是明确的:「Python 中一切皆对象」. 那么,这到底意味着什么呢? 如下代码: #!/usr/bin/env python a = [0, 1, 2] # 来个简单的list # 最初,list 和其中各个元素的id 是这样的. print 'origin' print id(a),a for x in a: print id(x), x print '----------------------' # 我们把

python中的“引用”和C++的引用

python并不刻意区分“按值传递”和“按引用传递”. 在底层,python将值分为不可变对象(比如int,str)和可变对象(比如列表).所有的变量都是对某个对象的引用,赋值(=)和函数参数传递,都将改变变量所引用的对象. 对于不可变对象,赋值和传参将导致新创建对象,这和C++的引用行为是不同的.此时,赋值和传参是按值传递. 对于可变对象,赋值和传参,和C++引用的行为一致,是真正的按引用传递.

python中的引用和复制

对象引用 >>> a = [1,2,3,4] >>> b = a >>> b is a True >>> b[2] = -100 >>> b [1, 2, -100, 4] >>> a [1, 2, -100, 4] a和b引用的是同一个对象,修改其中的一个将影响另一个. 对于像列表和字典这样的容器对象,可以使用浅复制和深复制. 浅复制 浅复制可以创建一个新对象,包含的是对原始对象中包含的项的引用:

Python中循环引用(import)失败的解决方法

原文链接:http://blog.ihuxu.com/the-solution-to-the-problem-of-circular-import-in-python/ 我是采用方案三 "将引用放到函数内部"解决了这个问题.下面为原文. 前言 最近在开发智能家居项目hestia-rpi项目中,由于代码结构层级划分不合理,导致了循环引用(import)module失败的问题,错误如下: Traceback (most recent call last):  File "./ma

python中循环引用导致内存泄漏小案例

首先定义一个Person类和一个Dog类,然后分别实例化对象p和d,给p对象添加一个pet属性 给d对象添加一个master属性此时Person和Dog的应用计数都为2,当del p 和del d后Person 和Dog的应用计数都为1,就造成了循环引用导致内存不能释放 最终导致内存泄漏. 以下图片是没有循环应用的代码执行结果 以下图片是循环引用后代码执行结果 原文地址:https://www.cnblogs.com/chen55555/p/11079223.html

浅谈python中的引用和拷贝问题

一.引用 a = ['a', 'b', 'c'] b = a print(id(a)) print(id(b)) 135300560 135300560 可以看到,变量a 和 b 的 id是完全一样的,这就说明a和b是同时指向内存的同一个区域的,即b随a的变化而变化. a = ['a', 'b', 'c'] b = a a[1] = 'd' print(b) b[2] = 'e' print(a) ['a', 'd', 'c'] ['a', 'd', 'e'] 二.浅拷贝 浅拷贝只是复制了的父对

从python中copy与deepcopy的区别看python引用

讨论copy与deepcopy的区别这个问题要先搞清楚python中的引用.python的内存管理. python中的一切事物皆为对象,并且规定参数的传递都是对象的引用.可能这样说听起来比较难懂,对比一下PHP中的赋值和引用就有大致的概念了.参考下面一段引用: 1. python不允许程序员选择采用传值还是传引用.Python参数传递采用的肯定是“传对象引用”的方式.实际上,这种方式相当于传值和传引用的一种综合.如果函数收到的是一个可变对象(比如字典或者列表)的引用,就能修改对象的原始值——相当

Python中List的append引用赋值问题处理

Python中的对象之间赋值时是按引用传递的,如果需要拷贝对象,需要使用标准库中的copy模块. 1. copy.copy 浅拷贝 只拷贝父对象,不会拷贝对象的内部的子对象. 2. copy.deepcopy 深拷贝 拷贝对象及其子对象程序: import copy a = [1, 2, 3, 4, ['a', 'b']] #原始对象 b = a #赋值,传对象的引用 c = copy.copy(a) #对象拷贝,浅拷贝 d = copy.deepcopy(a) #对象拷贝,深拷贝 a.appe