49 list_排序算法和深浅copy

能征服人心的,永远不是聪明和强势,——而是善良;
能感动人心的,永远不是语言和忽悠,——而是真诚;


0 函数帮助文档查看: lst.sort? lst.sort??

1.列表排序

排序算法也有内外之分:

内部排序指的是在内存中进行排序;
外部排序指的是由于数据量较大,无法读入内存而需要在排序过程中访问外部存储的情况;

经典的排序算法如下

Python 列表有内置就地排序的方法 list.sort(),返回None此外还有一个内置的 sorted() 函数将一个可迭代对象(iterable)排序为一个新的有序列表;

1.1 排序基础——list.sorted与sorted差别

1.sorted(iterable, /, *, key=None, reverse=False),得到一个有序的新列表;

>>> sorted([5, 2, 3, 1, 4])
[1, 2, 3, 4, 5]

2.list.sort() 方法,此方法为就地排序(并且返回 None 来避免混淆)。通常来说这不如 sorted() 方便——但是当你不需要保留原始列表的时候,这种方式略高效一些。

>>> a = [5, 2, 3, 1, 4]
>>> a.sort()
>>> a[1, 2, 3, 4, 5]

3.另外一个区别是 list.sort() 方法只可以供列表使用,而 sorted() 函数可以接受任意可迭代对象(iterable)。

>>> sorted({1: 'D', 2: 'B', 3: 'B', 4: 'E', 5: 'A'})
[1, 2, 3, 4, 5]
1.2 Key 参数

list.sort() 和 sorted() 都有一个 key 参数,用于指定在作比较之前,调用何种函数(str / int)对列表元素进行处理。

>>> sorted("This is a test string from Andrew".split(), key=str.lower)
['a', 'Andrew', 'from', 'is', 'string', 'test', 'This']

key 参数的值应该是一个函数,该函数接收一个参数,并且返回一个 key 为排序时所用。这种方法(高阶函数)速度很快,因为每个输入项仅调用一次 key 函数;

>>> student_tuples = [
    ('john', 'A', 15),
    ('jane', 'B', 12),
    ('dave', 'B', 10),]
>>> sorted(student_tuples, key=lambda student: student[2])   # sort by age
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]

2.浅Copy与深Copy

引用、浅拷贝和深拷贝的区别

lst=[1,2,3,4]
lst1=lst # 同一个对象,指向同一个东西
lst2=lst.copy() # 内容相同,不同的对象,遇到引用类型不会复制对象,只会复制地址
lst3=copy.deepcopy(lst) # 内容相同,但不同的对象,如果有引用类型也会复制出不同的对象

浅拷贝:为了解决函数传递后被修改的问题,就需要拷贝一份副本,将副本传递给函数使用,就算是副本被修改,也不会影响原始数据 。

深拷贝:深拷贝使复制过程递归。这意味着首先构造一个新的集合对象,然后递归地用在原始对象中找到的子对象的副本填充它。以这种方式复制一个对象,遍历整个对象树,以创建原始对象及其所有子对象的完全独立的克隆。

数据拷贝会涉及到Python中对象、可变类型、引用这3个概念,先来看看这几个概念,只有明白了他们才能更好的理解深拷贝与浅拷贝到底是怎么一回事。

2.1** Python对象**都拥有三个属性:身份、类型、值。
In [2]: id(name)  # id:身份的唯一标识
Out[2]: 1698668550104
In [3]: type(name) # type:对象的类型,决定了该对象可以保存什么类型的值
Out[3]: str
In [4]: name  # 对象的值,表示的数据
Out[4]: 'laowang'
可变与不可变对象
可变对象: 列表、字典、集合

所谓可变是指可变对象的值可变,身份是不变的。

不可变对象:数字、字符串、元组

不可变对象就是对象的身份和值都不可变。新创建的对象被关联到原来的变量名,旧对象被丢弃,垃圾回收器会在适当的时机回收这些对象。

引用=id()

引用实际就是内存中的一个数字地址编号,在使用对象时,只要知道这个对象的地址,就可以操作这个对象,但是因为这个数字地址不方便在开发时使用和记忆,所以使用变量名的形式来代替对象的数字地址。 在 Python 中,变量就是地址的一种表示形式,并不开辟开辟存储空间

不可变对象的拷贝

不可变对象只在修改的时候才会在内存中开辟新的空间, 而拷贝实际上是让多个对象同时指向一个引用,和对象的赋值没区别。

In [11]: import copy
In [12]: a = 10
In [13]: b = copy.copy(a)
In [14]: id(a)
Out[14]: 1730306496
In [15]: id(b)
Out[15]: 1730306496
可变对象的拷贝

可变对象的拷贝,会在内存中开辟一个新的空间来保存拷贝的数据。当再改变之前的对象时,对拷贝之后的对象没有任何影响。

In [25]: l1 = [1, 2, 3]
In [26]: l2 = copy.copy(l1)
In [27]: id(l1)
Out[27]: 1916631742088
In [28]: id(l2)
Out[28]: 1916636282952
In [29]: l1[0] = 11
In [30]: id(l1)
Out[30]: 1916631742088
In [31]: id(l2)
Out[31]: 1916636282952

同样的,通过一个实例来感受一下:不难看出,a与b指向相同的引用,不可变对象的拷贝就是对象赋值。

复杂对象在拷贝时,并没有解决数据在传递之后,数据改变的问题。 出现这种原因,是copy() 函数在拷贝对象时,只是将指定对象中的所有引用拷贝了一份,如果这些引用当中包含了一个可变对象的话,那么数据还是会被改变。 这种拷贝方式,称为浅拷贝。

深拷贝——解决原始数据改变的问题

区别于浅拷贝只拷贝顶层引用,深拷贝会逐层进行拷贝,直到拷贝的所有引用都是不可变引用为止。

l1 = [3, 4, a]
In [47]: l2 = copy.deepcopy(li)
In [48]: id(l1)
Out[48]: 1916632194312
In [49]: id(l2)
Out[49]: 1916634281416
In [50]: a[0] = 11
In [51]: id(l1)
Out[51]: 1916632194312
In [52]: id(l2)
Out[52]: 1916634281416
In [54]: l1
Out[54]: [3, 4, [11, 2]]
In [55]: l2
Out[55]: [1, 2, 3]
查漏补缺

1.为什么Python默认的拷贝方式是浅拷贝?
时间角度:浅拷贝花费时间更少
空间角度:浅拷贝花费内存更少
效率角度:浅拷贝只拷贝顶层数据,一般情况下比深拷贝效率高。

本文知识点总结:

1.不可变对象在赋值时会开辟新空间
2.可变对象在赋值时,修改一个的值,另一个也会发生改变
3.深、浅拷贝对不可变对象拷贝时,不开辟新空间,相当于赋值操作
4.浅拷贝在拷贝时,只拷贝第一层中的引用,如果元素是可变对象,并且被修改,那么拷贝的对象也会发生变化
5.深拷贝在拷贝时,会逐层进行拷贝,直到所有的引用都是不可变对象为止。
6.Python 中有多种方式实现浅拷贝,copy模块的copy 函数 ,对象的 copy 函数 ,工厂方法,切片等。
7.大多数情况下,编写程序时,都是使用浅拷贝,除非有特定的需求
8.浅拷贝的优点:拷贝速度快,占用空间少,拷贝效率高

深度解读Python深拷贝与浅拷贝问题

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容

  • http://python.jobbole.com/85231/ 关于专业技能写完项目接着写写一名3年工作经验的J...
    燕京博士阅读 7,545评论 1 118
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,082评论 1 32
  • 个人笔记,方便自己查阅使用 Py.LangSpec.Contents Refs Built-in Closure ...
    freenik阅读 67,677评论 0 5
  • 前言 把《C++ Primer》[https://book.douban.com/subject/25708312...
    尤汐Yogy阅读 9,500评论 1 51
  • 任何人问起我北漂那几年的经历时,我都是特自豪的说,挺好的。即便,第一份工只是一个前台小妹,即便每天挤公交都需要交通...
    熊小样阅读 103评论 0 0