本文最后更新于: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的底层对象的值。

深拷贝是在另一块地址中创建一个新的变量或容器,同时容器内的元素的地址也是新开辟的,仅仅是值相同而已,是完全的副本。

二维数组初始化

python创建二维数组

# 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()

enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据下标和数据,一般用在 for 循环当中。

>>>seq = ['one', 'two', 'three']
>>>for i, element in enumerate(seq):
...    print(i, seq[i])
... 
0 one
1 two
2 three

zip()

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]

reversed(seq)

返回一个反转的迭代器;参数:要转换的序列,可以是tuple, string, list 或 range。

# 字符串
>>> seqString = 'Runoob'
>>> print(list(reversed(seqString)))

['b', 'o', 'o', 'n', 'u', 'R']

eval()

eval() 函数用来执行一个字符串表达式,返回表达式的值。

>>> x = 7
>>> eval( '3 * x' )
21
>>> eval('pow(2,2)')
4
>>> eval('2 + 2')
4
>>> n=81
>>> eval("n + 4")
85

bin()

返回整数 int 或者长整数 long int 的二进制表示。

>>> bin(11)
'0b1011'
>>> bin(20)
'0b10100'
str = 
>>> str = "1010"
>>> int(str, base=2)
10

getattr()

getattr(object, name[, default]) 函数用于返回一个对象属性值。用例,leetcode习题解6:链表组件。

class A(object):
    bar = 1
>>> a = A()
>>> getattr(a, 'bar')  # 获取属性 bar1

maketrans()

str.maketrans(intab_str, outtab_str) 创建字符映射的转换表。第一个参数表示需要转换的字符,第二个表示转换的目标。两个字符串的长度必须相同,为一一对应关系

translate()

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'

join()

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()

os.path 模块主要用于获取文件的属性。

find()

str.find(str, beg=0, end=len(string))。Python find() 方法检测字符串中是否包含子字符串 str ,如果指定 beg(开始) 和 end(结束) 范围,则检查是否包含在指定范围内,如果包含子字符串返回开始的索引值,否则返回-1。

isalpha()

isalpha() 方法检测字符串是否只由字母组成。如果字符串至少有一个字符并且所有字符都是字母则返回 True,否则返回 False。

all()

all() 函数用于判断给定的可迭代参数 iterable 中的所有元素是否都为 TRUE,如果是返回 True,否则返回 False。元素除了是 0、空、None、False 外都算 True。

富比较

Python中基类object提供了一系列可以用于实现同类对象进行“比较”的方法,可以用于同类对象的不同实例进行比较,包括 ltgtlegeeqne 六个方法。

排列组合

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')]

cmp_to_key

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常用数据结构的操作的时间复杂度。

参考一

参考

python3.7.6文档:内置类型

Python知识点汇总

Python3教程

Python语言中的引用与拷贝

Python标准库模块之heapq

为什么Python中称lt、gt等为“富比较”方法


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!

Java 基础 上一篇