python copy详解

【原文】http://hi.baidu.com/feng2211/blog/item/0656758bd06f54729f2fb47b.html

需求:

你想复制一个对象.因为在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.

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
shutil是Python自带的标准库之一,它提供了许多文件和文件夹的操作函数,可以方便地对文件和文件夹进行复制、移动、删除等操作。下面是shutil库中常用的一些函数: 1. shutil.copy(src, dst):复制文件,将src文件复制到dst路径下,返回目标路径。如果dst是文件夹,则复制到该文件夹下,并以src文件名命名。 2. shutil.copy2(src, dst):复制文件,与copy类似,但是会尽量保留文件的元数据(如权限、时间戳等)。 3. shutil.copytree(src, dst):复制文件夹,将src文件夹复制到dst路径下,返回目标路径。 4. shutil.rmtree(path):删除文件夹,递归删除path下的所有文件和文件夹。 5. shutil.move(src, dst):移动文件或文件夹,将src移动到dst路径下,返回目标路径。 6. shutil.chown(path, user=None, group=None):修改文件或文件夹的所有者和所属组。 7. shutil.make_archive(base_name, format, root_dir=None, base_dir=None):创建压缩文件,将root_dir目录下的所有文件和文件夹打包成压缩文件,保存到base_name路径下,以format格式(如zip、tar)压缩。 8. shutil.unpack_archive(filename, extract_dir=None, format=None):解压缩文件,将filename压缩文件解压缩到extract_dir目录下,以format格式(如zip、tar)解压缩。 使用shutil库需要注意以下几点: 1. shutil库中的函数可以直接操作文件和文件夹,但需要注意路径的格式,Windows系统下需要使用反斜杠(\)分隔路径,Linux系统下需要使用正斜杠(/)分隔路径。 2. shutil库中的函数对文件和文件夹的操作是不可逆的,因此在使用时需要谨慎操作,以防数据丢失。 3. 在使用shutil.copytree()函数时,如果目标路径下已经存在同名文件夹,则会抛出FileExistsError异常。可以通过设置shutil.copytree()函数的ignore参数来忽略该异常,如shutil.copytree(src, dst, ignore=shutil.ignore_patterns('.svn', '.git')),该函数将忽略名为'.svn'和'.git'的文件夹。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值