本文最后更新于:2020年7月29日 上午
Python知识点整理。
Python中的引用与拷贝
区别
引用:旧瓶装旧酒
浅拷贝:新瓶装旧酒
深拷贝:新瓶装新酒
引用
python中赋值符号“=”两边的对象是同一个对象,左边的对象可以看成是右边对象的一个引用。
>>> a=[1,2,'a','b']
>>> b=a
>>> a
[1, 2, 'a', 'b']
>>> b
[1, 2, 'a', 'b']
>>> a.append('c')
>>> a
[1, 2, 'a', 'b', 'c']
>>> b
[1, 2, 'a', 'b', 'c']
>>> a is b
True
a的值的变化会导致b的值也会变化,因为他们是同一个对象,共享同一块内存地址,b是a的引用。
判断两个变量是否是同一个对象的方法是用is,返回True则代表两个变量是同一个对象。
赋值是将一个对象的地址赋值给一个变量,让变量指向该地址。
拷贝
对象的拷贝是根据源对象生成一个新的对象,占用不同的内容存空间。一个对象值的变化,不会影响另外一个对象的值。拷贝又分潜拷贝和深拷贝。
浅拷贝
python中的copy模块可以实现对象的浅拷贝。
>>> import copy
>>> a=[[1,2],['a','b']]
>>> b=copy.copy(a)
>>> b is a
>>> False
>>> a.append('c')
>>> a
[[1, 2], ['a', 'b'], 'c']
>>> b
[[1, 2], ['a', 'b']]
>>> a[0].append(3)
>>> a
[[1, 2, 3], ['a', 'b'], 'c']
>>> b
[[1, 2, 3], ['a', 'b']]
>>> a[0] is b[0]
>>> True
# b=a[:]会创建一个新的与a完全相同的对象,但是与a并不指向同一对象
>>> a = [1,2,3,[4,5]]
>>> b = a[:]
>>> b
[1, 2, 3, [4, 5]]
>>> a is b
False
>>> a.append(7)
>>> a
[1, 2, 3, [4, 5], 7]
>>> b
[1, 2, 3, [4, 5]]
>>> a[3].append(9)
>>> a
[1, 2, 3, [4, 5, 9], 7]
>>> b
[1, 2, 3, [4, 5, 9]]
>>> a[3] is b[3]
True
>>>
通过例子可以看到通过copy模块的copy方法,根据对象a生成了一个新对象b,这一点可以通过is表达式的结果证明。
a.append(‘c’)之后,发现a和b的值不一样了,这是因为a和b指向两个不同的地址。对a的值的修改不会影响b的值。 但是a[0].append(3)之后,a[0]和b[0]却是一样的。这就是浅拷贝的效果。因为a[0] 和b[0]还是指向同一个地址。
浅拷贝是在另一块地址中创建一个新的变量或容器,但是容器内的元素的地址均是源对象的元素的地址的拷贝。也就是说新的容器中指向了旧的元素。
深拷贝
python的copy模块的deepcopy函数可以实现深拷贝。
>>> import copy
>>> a=[[1,2],['a','b']]
>>> b=copy.deepcopy(a)
>>> a is b
False
>>> a[0] is b[0]
False
>>> a.append('c')
>>> a
[[1, 2, 3], ['a', 'b'], 'c']
>>> b
[[1, 2], ['a', 'b']]
>>> a[0].append(3)
>>> a
[[1, 2, 3], ['a', 'b']]
>>> b
[[1, 2], ['a', 'b']]
由于b是a的深拷贝,所以a对象和b对象的内存地址不同,a对象和b对象包含的底层对象(a[0]a[1]b[0]b[1])内存地址也不同。
对a对象的值的改变不会影响b对象的值,对a对象的底层对象的值的改变也不会影响b的底层对象的值。
深拷贝是在另一块地址中创建一个新的变量或容器,同时容器内的元素的地址也是新开辟的,仅仅是值相同而已,是完全的副本。
二维数组初始化
# list * n—>n shallow copies of list concatenated, n个list的浅拷贝的连接
>>> dimen_list = [[0] * 3] * 4
>>> dimen_list
[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
>>> dimen_list[0][1] = 1
>>> dimen_list
[[0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0]]
>>> lists = [[]] * 3
>>> lists
[[], [], []]
>>> lists[0].append(3)
>>> lists
[[3], [3], [3]]
# 需要用另一种方式创建多维数组,以免浅拷贝
>>> size = 3
>>> lists = [[0 for _ in range(size)] for _ in range(size)]
>>> lists
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
内置类型
Python内置类型:主要有数字、序列、映射、类、实例和异常。
数字类型:int, float, complex
迭代器类型:Python 支持对容器进行迭代。序列支持迭代方法。
生成器类型:Python 的 generator 提供了一种实现迭代器协议的便捷方式。
不可变序列类型:数字、布尔、元组tuple、range 类型表示不可变的数字序列、文本序列类型(字符串)str、bytes、frozenset
注:由于许多主要二进制协议都基于 ASCII 文本编码,因此 bytes 对象提供了一些仅在处理 ASCII 兼容数据时可用,并且在许多特性上与字符串对象紧密相关的方法。
可变序列类型:列表list、字典dic、set,不可以作为字典的key
不可变序列类型普遍实现,而可变序列类型未实现的操作是对 hash() 内置函数的支持。也就是说,hash() 函数可以应用于数字、字符串和对象,但是不能直接应用于list、set、dictionary。
列表解析式:[x*2 for x in range(10)]
字典解析式:my_dict = {i: i * i for i in range(10)}
集合解析式:my_set = {i * 15 for i in range(100)}
字符串/列表逆序:
>>> str = "abc"
>>> str[::-1] # 原字符串不改变
'cba'
>>> ''.join(reversed(str)) # 原字符串不改变
'cba'
>>> a = [1,2,3,4]
>>> a[::-1] # 原列表不改变
[4, 3, 2, 1]
>>> a.reverse() # 原列表改变
>>> a
[4, 3, 2, 1]
空对象:当函数无显示返回值时,会返回该对象。它不支持任何特殊的操作。空对象只有一种值 None (内置名称)。
优先队列的特点:队列的特点是先进先出,入队时,将新元素置于队尾巴,出队时,队头元素最先被移出。优先队列不再遵循先入先出的原则,而分为两种情况:1)最大优先队列,无论入队顺序如何,都是当前最大的元素出队;2)最小优先队列,无论入队顺序如何,都是当前最小的元素出队。
优先队列的实现:二叉堆有以下性质:1)最大堆的堆顶是整个堆中的最大元素;2) 最小堆的堆顶是整个堆中的最小元素。因此,可以用最大堆来实现最大优先队列,每一次入队操作就是堆的插入操作,每一次出队操作就是删除堆顶节点。二叉堆节点上浮和下沉的时间复杂度都是O(logn),所以优先队列的入队和出队的时间复杂度也是O(logn)。
python中heapq模块实现了最小堆。heapq有两种方式创建堆:1)使用一个空列表,然后使用heapq.heappush()方法将值加入堆中;2)使用heap.heapify(list)转换列表成为堆结构。
heapify(heap) | 让列表具备堆特征 |
---|---|
heappush(heap, x) | 将x压入堆中 |
heappop(heap) | 从堆中弹出最小的元素 |
heapreplace(heap, x) | 弹出最小的元素,并将x压入堆中 |
nlargest(n, iter) | 返回iter中n个最大的元素 |
nsmallest(n, iter) | 返回iter中n个最小的元素 |
常用方法
enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据下标和数据,一般用在 for 循环当中。
>>>seq = ['one', 'two', 'three']
>>>for i, element in enumerate(seq):
... print(i, seq[i])
...
0 one
1 two
2 three
zip() 函数将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的对象,这样做的好处是节约了不少的内存。可以使用 list() 转换来输出列表。如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用 ***** 号操作符,可以将元组解压为列表。
>>> a = [1,2,3]
>>> b = [4,5,6]
>>> c = [4,5,6,7,8]
>>> zipped = zip(a,b) # 返回一个对象
>>> zipped
<zip object at 0x103abc288>
>>> list(zipped) # list() 转换为列表
[(1, 4), (2, 5), (3, 6)]
>>> list(zip(a,c)) # 元素个数与最短的列表一致
[(1, 4), (2, 5), (3, 6)]
>>> a1, a2 = zip(*zip(a,b)) # 与 zip 相反,zip(*) 可理解为解压,返回二维矩阵式
>>> list(a1)
[1, 2, 3]
>>> list(a2)
[4, 5, 6]
返回一个反转的迭代器;参数:要转换的序列,可以是tuple, string, list 或 range。
# 字符串
>>> seqString = 'Runoob'
>>> print(list(reversed(seqString)))
['b', 'o', 'o', 'n', 'u', 'R']
eval() 函数用来执行一个字符串表达式,返回表达式的值。
>>> x = 7
>>> eval( '3 * x' )
21
>>> eval('pow(2,2)')
4
>>> eval('2 + 2')
4
>>> n=81
>>> eval("n + 4")
85
返回整数 int 或者长整数 long int 的二进制表示。
>>> bin(11)
'0b1011'
>>> bin(20)
'0b10100'
str =
>>> str = "1010"
>>> int(str, base=2)
10
getattr(object, name[, default]) 函数用于返回一个对象属性值。用例,leetcode习题解6:链表组件。
class A(object):
bar = 1
>>> a = A()
>>> getattr(a, 'bar') # 获取属性 bar 值
1
str.maketrans(intab_str, outtab_str) 创建字符映射的转换表。第一个参数表示需要转换的字符,第二个表示转换的目标。两个字符串的长度必须相同,为一一对应关系
translate() 方法根据参数table给出的表(包含 256 个字符)转换字符串的字符,要过滤掉的字符放到 deletechars 参数中。
intab = "aeiou"
outtab = "12345"
trantab = str.maketrans(intab, outtab) # 制作翻译表
str = "this is string example....wow!!!"
print (str.translate(trantab))
# th3s 3s str3ng 2x1mpl2....w4w!!!
ord() 和 chr()
ord() 和 chr() 方法将字母和ASCII相互转化。
>>> ord('A')
65
>>> chr(65)
'A'
str.join(sequence) 方法用于将序列中的元素以指定的字符连接生成一个新的字符串,sequence为要连接的元素序列。返回通过指定字符连接序列中元素后生成的新字符串。
str = "-"
seq = ("a", "b", "c")
print str.join(seq)
# a-b-c
list = ['1', '2', '3']
print(''.join(list))
# 123
seq = {'hello': 1, 'world': 2}
print('-'.join(seq)) # 字典只对键进行连接
# hello-world
import os
print os.path.join("D:\\","test.txt") # 连接2个字符串
# D:\test.txt
# file_path存放于E:\PySec
print(os.path.abspath('.'))
print(os.path.dirname(os.path.abspath('.'))) # abspath('.')返回当前目录的绝对路径
file_dir = os.path.dirname(os.path.abspath('.')) + 'data'
lists = os.listdir(file_dir)
print(lists)
file = os.path.join(file_dir, lists[-1])
print(file)
# E:\PySec
# E:\
# ['DAG reference.pdf', 'formatted.csv', 'formatted_1.csv', 'formatted_2.csv', 'Pro_process.docx']
# E:\data\Pro_process.docx
os.path 模块主要用于获取文件的属性。
str.find(str, beg=0, end=len(string))。Python find() 方法检测字符串中是否包含子字符串 str ,如果指定 beg(开始) 和 end(结束) 范围,则检查是否包含在指定范围内,如果包含子字符串返回开始的索引值,否则返回-1。
isalpha() 方法检测字符串是否只由字母组成。如果字符串至少有一个字符并且所有字符都是字母则返回 True,否则返回 False。
all() 函数用于判断给定的可迭代参数 iterable 中的所有元素是否都为 TRUE,如果是返回 True,否则返回 False。元素除了是 0、空、None、False 外都算 True。
Python中基类object提供了一系列可以用于实现同类对象进行“比较”的方法,可以用于同类对象的不同实例进行比较,包括 lt、gt、le、ge、eq和ne 六个方法。
python的itertools包中提供了和排列组合相关的函数:
- combinations方法重点在组合
- permutations方法重在排列
- product 用于求多个可迭代对象的笛卡尔积(Cartesian Product),它跟嵌套的 for循环等价。即:product(A, B) 和 ((x,y) for x in A for y in B)的效果是一样的。
>>> from itertools import combinations, permutations, product
>>> list(combinations('abc',2))
[('a', 'b'), ('a', 'c'), ('b', 'c')]
>>> list(permutations('abc',2))
[('a', 'b'), ('a', 'c'), ('b', 'a'), ('b', 'c'), ('c', 'a'), ('c', 'b')]
>>> list(product('abc',repeat=2))
[('a', 'a'), ('a', 'b'), ('a', 'c'), ('b', 'a'), ('b', 'b'), ('b', 'c'), ('c', 'a'), ('c', 'b'), ('c', 'c')]
>>> list(product('abc','de'))
[('a', 'd'), ('a', 'e'), ('b', 'd'), ('b', 'e'), ('c', 'd'), ('c', 'e')]
from functools import cmp_to_key
L=[9,2,23,1,2]
sorted(L,key=cmp_to_key(lambda x,y:y-x))
# Output:
# [23, 9, 2, 2, 1]
sorted(L,key=cmp_to_key(lambda x,y:x-y))
# [1, 2, 2, 9, 23]
时间复杂度
总结Python常用数据结构的操作的时间复杂度。
参考
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!