python采用的是引用变量的结构,也就说如果你对一个变量赋值,并不是给这个变量开辟了一块内存空间而是将一个对象的内存空间地址告诉了这个变量,这样做的好处是便于管理,节省内存空间,便于内存释放等等。但是在一些特殊情况下还是需要一个有自己内存空间的变量,这样操作起来和原变量互不干扰。那就要用到对象的复制了。

接下来看看变量的复制如何操作:

需求:

你想复制一个对象.因为在Python中,无论你把对象做为参数传递,做为函数返回值,都是引用传递的.

讨论:

标准库中的copy模块提供了两个方法来实现拷贝.一个方法是copy,它返回和参数包含内容一样的对象.

import copy
new_list = copy.copy(existing_list)

有些时候,你希望对象中的属性也被复制,可以使用deepcopy方法:

import copy
new_list_of_dicts = copy.deepcopy(existing_list_of_dicts)

当你对一个对象赋值的时候(做为参数传递,或者做为返回值),Python和Java一样,总是传递原始对象的引用,而不是一个副本.其它一些语言当赋值的时候总是传递副本.Python从不猜测用户的需求 ,如果你想要一个副本,你必须显式的要求.
Python的行为很简单,迅速,而且一致.然而,如果你需要一个对象拷贝而并没有显式的写出来,会出现问题的,比如:
>>> a = [1, 2, 3]
>>> b = a
>>> b.append(5)
>>> print a, b
[1, 2, 3, 5] [1, 2, 3, 5]
在这里,变量a和b都指向同一个对象(一个列表),所以,一旦你修改了二者之一,另外一个也会受到影响.无论怎样,都会修改原来的对象.
注意:
要想成为一个Python高手,首先要注意的问题就是对象的变更操作和赋值,它们都是针对对象的引用操作的.一个语句比如a = []将a重新绑定给一个新对象,但不会影响以前的对象.然而,对象复制却不同,当对象复制后,对象变更操作就有了区别.
如 果你想修改一个对象,而且想让原始的对象不受影响,那你就需要对象复制.正如本节说的一样,你可以使用copy模块中的两个方法来实现需求.一般的,可以 使用copy.copy,它可以进行对象的浅复制(shallow copy),它复制了对象,但对于对象中的元素,依然使用引用.
浅复制,有时无法获得一个和原来对象完全一致的副本,如果你想修改对象中的元素,不仅仅是对象本身的话:

>>> list_of_lists = [ ['a'], [1, 2], ['z', 23] ]
>>> copy_lol = copy.copy(lists_of_lists)
>>> copy_lol[1].append('boo')
>>> print list_of_lists, copy_lol
[['a'], [1, 2, 'boo'], ['z', 23]] [['a'], [1, 2, 'boo'], ['z', 23]]

在这里,变量list_of_lists,copy_lol指向了两个不同的对象,所以我们可以修改它们任何一个, 而不影响另外一个.然而,如果我们修改了一个对象中的元素,那么另一个也会受影响,因为它们中的元素还是共享引用.
如果你希望复制一个容器对象,以及它里面的所有元素(包含元素的子元素),使用copy.deepcopy,这个方法会消耗一些时间和空间,不过,如果你需要完全复制,这是唯一的方法.
对于一般的浅拷贝,使用copy.copy就可以了,当然,你需要了解你要拷贝的对象.要复制列表L,使用list(L),要复制一个字典d,使用dict(d),要复制一个集合s,使用set(s),这样,我们总结出一个规律,如果你要复制一个对象o,它属于内建的类型t,那么你可以使用t(o)来 获得一个拷贝.dict也提供了一个复制版本,dict.copy,这个和dict(d)是一样,我推荐你使用后者,这个使得代码更一致,而且还少几个字符.
要复制一个别的类型,无论是你自己写的还是使用库中的,使用copy.copy,如果你自己写一个类,没有必要费神去写clone和copy函数,如果你想定义自己的类复制的方式,实现一个__copy__,或者__getstate__和__setstate__.如果你想定义自己类型的deepcopy,实现方法__deepcopy__.
注意你不用复制不可修改对象(string,数字,元组),因为你不用担心修改它们.如果你想尝试一下复制,依然会得到原来的.虽然无伤大雅,不过真的浪费尽力:

>>> s = 'cat'
>>> t = copy.copy(s)
>>> s is t
True

is操作符用于不仅判断两个对象是否完全一致,而且是同一个对象(is判断标识符,要比较内容,使用==),判断标识符是否相等对于不可修改对象没有什么意义.然而 ,判断标识符对于可修改对象有时候是很重要的,比如,你不确定a和b是否指向同一个对象,使用a is b会立刻得到结果.这样你可以自己判断是否需要使用对象拷贝.
注意:
你可以使用另一种拷贝方式,给定一个列表L,无论是完整切片L[:]或者列表解析[x for x in L],都会获得L的浅拷贝,试试L+[],L*1...但是上面两种方法都会使人迷惑,使用list(L)最清晰和快速,当然,由于历史原因,你可能会经常看到L[:]的写法.
对于dict,你可能见过下面的复制方法:
>>> for somekey in d:
... d1[somekey] = d[somekey]

或者更简单一些的方法,d1={},d1.update(d),无论怎样,这些代码都是缺乏效率的,使用d1=dict(d)吧.

相关说明:

copy(x)
Shallow copy operation on arbitrary Python objects.

See the module's __doc__ string for more info.

deepcopy(x, memo=None, _nil=[])
Deep copy operation on arbitrary Python objects.

See the module's __doc__ string for more info.

Python面试题目之Python的复制和赋值浅析的更多相关文章

  1. Python面试题目之Python函数默认参数陷阱

    请看如下一段程序: def extend_list(v, li=[]): li.append(v) return li list1 = extend_list(10) list2 = extend_l ...

  2. Python面试题目--汇总

    原文链接-https://github.com/taizilongxu/interview_python Python语言特性 1 Python的函数参数传递 2 Python中的元类(metacla ...

  3. python面试题目

    问题一:以下的代码的输出将是什么? 说出你的答案并解释. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Parent(object):     x = 1   clas ...

  4. python面试题目【转1】

    原文地址:https://www.usblog.cc/blog/post/justzhl/b5cc9a05c7d2 问题一:以下的代码的输出将是什么? 说出你的答案并解释. 1 2 3 4 5 6 7 ...

  5. Python面试题目之深浅拷贝浅析

    # copy.copy 浅拷贝 只拷贝父对象,不会拷贝对象的内部的子对象. **只是简单的指针赋值 # copy.deepcopy 深拷贝 拷贝对象及其子对象 **指针赋值,且内容拷贝 用一个简单的例 ...

  6. Python面试题目之(针对dict或者set数据类型)边遍历 边修改 报错dictionary changed size during iteration

    # result 是一个字典, 把里面属性值是None的属性删除 for key in result: if not result[key]: del result[key] continue 但是报 ...

  7. Python面试题目之列表去重并维持原来顺序

    题目: 列表去掉重复元素,并保持原来的排序 方法一: # 待处理的列表 L1 = [111,44,55,33,22,11] # 利用集合set的属性,去重 s1 = set(L1) # 把集合转化为列 ...

  8. Python面试题目之列表取值超出范围

    # 下面列表取值超出范围,会报错还是有返回值: L1 = [',]print(L1[10]) print(L1[10:]) 第一个打印会报错: 第二个打印会返回一个空列表

  9. Python面试题目之打乱打乱有序列表

    # 要求打乱一个有序列表 # 待处理列表 L1 = [11,22,33,44,55,66,77,] 方法: # 引入random模块,该模块的shuffle方法见下图 import random L1 ...

随机推荐

  1. 获取jqGrid中选择的行的数据以及 jqGrid获得所有行数据的方法

    获取jqGrid中选择的行的数据: 获取选择一行的id,如果你选择多行,那下面的id是最后选择的行的id:   1 var id=$('#gridTable').jqGrid('getGridPara ...

  2. HDU4417 (Super Mario)

    题目链接:传送门 题目大意:一个大小为 n 的数组,m组询问,每组询问[x,y]内<=v的数的数量. 题目思路:主席树(注意询问时数组下标越界问题) #include <iostream& ...

  3. docker registry的https错误解决

    从docker1.3.2版本开始默认docker registry使用的是https,当你用docker pull 非https的docker regsitry的时候会报下面错误: Error: In ...

  4. Jquery 中的 event、event.target 和原生JS的 event、event.target 对比

    先看下原生的 event,如图: 再看下 Jquery 中的 event,如图: 明显不一样,也符合常理,比较结果: 那么如何把 Jquery 中的 event 转成原生的呢?  event.orig ...

  5. 160519、Oracle中将查询出的多条记录的某个字段拼接成一个字符串的方法

    with temp as( select 'China' nation ,'Guangzhou' city from dual union all select 'China' nation ,'Sh ...

  6. 20165330 2017-2018-2 《Java程序设计》第2周学习总结

    课本知识总结 第二章 基本数据类型与数组 标识符:标识类名.变量名.方法名.类型名.数组名及文件名的有效字符序列. 标识符的第一个字符不能是数字字符,且字母区分大小写. Java语言使用Unicode ...

  7. input即时————模糊匹配(纯html+jquery简单实现)

    <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <m ...

  8. Reference counted objects

    Reference counted objects · netty/netty Wiki https://github.com/netty/netty/wiki/Reference-counted-o ...

  9. ubuntu安装wine的方法

    使用命令行安装: 1.打开终端,使用命令:sudo apt-get install wine 2.它可能会出现选择哪个版本的安装,develop是开发版本,stable是稳定版本. 通常我们选择sta ...

  10. python(五)常用模块学习

    版权声明:本文为原创文章,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明. https://blog.csdn.net/fgf00/article/details/52357 ...