1、数值处理
1.1、内建常用数据类型
1.1.1、分类
数值型
int、float、complex、bool
序列sequence
字符串str、字节序列bytes、bytearray
列表list、元组tuple
键值对
集合set、字典dict
1.2、数值型
int、float、complex、bool都是class,1、5.0、2+3j都是对象即实例
int: python3的int就是长整型,且没有大小限制,受限于内存区域的大小
float: 由整数部分和小数部分组成。支持十进制和科学计数法表示。C的双精度型实现
complex: 有实数和虚数部分组成,实数和虚数部分都是浮点数,3+4.2J
bool: int的子类,仅有2个实例True、False对应1和0,可以和整数直接运
True=1和False=0为int的子类
1.2.1、bool: int的子类
bool(''), int(float('1.2')) ------>float转换的问题
(False, 1)
1.2.1.1、int + bool 隐式类型转换
123 + True , 123 + False -----> int + bool > int + int 隐式类型转换
(124, 123)
123 + False + 1.2 ----> int + bool + float => float 一定有隐式类型转换,仅仅限于数值计算中
124.2
1.2.1.2、强制类型转换
int(123 + False + 1.2)
124
image-20210825233546600
1.2.2、类型转换int_float_bool
int、float、complex、bool也可以当做内建函数对数据进行类型转换
int(x) 返回一个整数
float(x) 返回一个浮点数
complex(x)、complex(x,y) 返回一个复数
bool(x) 返回布尔值,前面讲过False等价的对象
1.2.3、整除
math模块的floor()、ceil()函数; 内建函数int()、round(); 运算符//
# 整除
print(3//2, 5//2, 7//2)
print(-3//2, -5//2, -7//2)
print(7//2, 7//-2, -7//2, -(7//2))
# int
print('int ------------')
print(int(1.4), int(1.5), int(1.6))
print(int(-1.4), int(-1.5), int(-1.6))
# ceil floor
print('ceil floor ------------')
import math
print(math.floor(2.5), math.floor(-2.5))
print(math.ceil(2.5), math.ceil(-2.5))
# round
print('round ------------')
print(round(1.4), round(-1.4), round(-1.6), round(1.6))
print(round(2.4), round(-2.4), round(2.6), round(2.6))
print('round .5 ---------')
print(round(0.5), round(1.5), round(2.5), round(3.5))
print(round(-0.5), round(-1.5), round(-2.5), round(-3.5))
round(),四舍六入五取偶
math.floor()向下取整
math.ceil()向上取整
int() 取整数部分
// 整除且向下取整
1.2.3.1、向下取正符号//
math.floor()向下取整
# // ------->向下取整
1//2, 2//2, 3//2, 4//2, 5//2,
(0, 1, 1, 2, 2) ------->计算后变成元组
# //
-1//2, -2//2, -3//2, -4//2, -5//2, ------->向下取整
(-1, -1, -2, -2, -3)
1.2.3.2、math.floor()向下取整
for i in (0, 0.5,1,1.2,1,5,1.7,2,2.1,2.5,2.8): #元组,可以迭代对象
print(i,math.floor(i)) #向下
0 0
0.5 0
1 1
1.2 1
1 1
5 5
1.7 1
2 2
2.1 2
2.5 2
2.8 2
for i in (0, 0.5,1,1.2,1,5,1.7,2,2.1,2.5,2.8):
print(-i,math.floor(-i)) #向下
0 0
-0.5 -1
-1 -1
-1.2 -2
-1 -1
-5 -5
-1.7 -2
-2 -2
-2.1 -3
-2.5 -3
-2.8 -3
1.2.3.3、math.ceil()向上取整
for i in (0, 0.5,1,1.2,1,5,1.7,2,2.1,2.5,2.8):
print(-i,math.ceil(-i))
0 0
-0.5 0
-1 -1
-1.2 -1
-1 -1
-5 -5
-1.7 -1
-2 -2
-2.1 -2
-2.5 -2
-2.8 -2
image-20210825213314777
1.2.3.4、int截取整数部分
for i in (0.0, 0.5,1.0,1.2,1.5,1.7,2.0,2.1,2.5,2.8):
print(i,int(i))
0.0 0
0.5 0
1.0 1
1.2 1
1.5 1
1.7 1
2.0 2
2.1 2
2.5 2
2.8 2
image-20210825214109025
1.2.3.4.1、int截取整数部分
for i in (0.0, 0.5,1.0,1.2,1.5,1.7,2.0,2.1,2.5,2.8):
print(-i,int(-i)) # int 转换为整型,复数,向上, int截取整数部分// floor;ceil
-0.0 0
-0.5 0
-1.0 -1
-1.2 -1
-1.5 -1
-1.7 -1
-2.0 -2
-2.1 -2
-2.5 -2
-2.8 -2
for i in (0.0, 0.5,1.0,1.2,1.5,1.7,2.0,2.1,2.5,2.8):
print("{}\t{}".format(-i,int(-i))) #取间隔相同
-0.0 0
-0.5 0
-1.0 -1
-1.2 -1
-1.5 -1
-1.7 -1
-2.0 -2
-2.1 -2
-2.5 -2
-2.8 -2
1.2.3.5、round(),四舍六入五取偶
1.2.3.5.1、四舍六入取整
for i in (0.0,1.2,1.7,2.0,2.1,2.8):
print("{}\t{}".format(i,round(i)))
0.0 0
1.2 1
1.7 2
2.0 2
2.1 2
2.8 3
image-20210825215400506
1.2.3.5.2、四舍六入取整
for i in (0.0,1.2,1.7,2.0,2.1,2.8):
print("{}\t{}".format(-i,round(-i)))
-0.0 0
-1.2 -1
-1.7 -2
-2.0 -2
-2.1 -2
-2.8 -3
for i in (0.5,1.5,2,5,3.5,-0.5,-1.5,-2.5,-3.5):
print("{}\t{}".format(-i,int(-i)))
-0.5 0
-1.5 -1
-2 -2
-5 -5
-3.5 -3
0.5 0
1.5 1
2.5 2
3.5 3
image-20210825220610555
1.2.4、常用数值处理函数
min()、max()
pow(x,y) 等于 x**y
math.sqrt() 等于 x ** 0.5
进制函数,返回值是字符串
bin()、oct()、hex()
math模块
math.pi π
math.e 自如常数
math模块中还有对数函数、三角函数等
1.2.4.1、min()、max()取最大最小
min(1,2,0), max(1,3,7,0)
(0, 7)
max? ----->查看解释
Docstring:
max(iterable, *[, default=obj, key=func]) -> value
max(arg1, arg2, *args, *[, key=func]) -> value
With a single iterable argument, return its biggest item. The
default keyword-only argument specifies an object to return if
the provided iterable is empty.
With two or more arguments, return the largest argument.
Type: builtin_function_or_method
image-20210825230605489
1.2.4.2、pow(x,y) 等于 x**y多少次方
2**3, pow(2,3),math.pow(2,3) ---->2的多少次方
(8, 8, 8.0)
image-20210825231005618
1.2.4.2.1、math.pow(,)开方
2**0.5,math.pow(2,0.5) ---->2的多少次方
(1.4142135623730951, 1.4142135623730951)
1.2.4.3、bin()输出字符串类型值
bin(10) ----->#输出为二进制字符串类型值
'0b1010'
image-20210825231827256
1.2.4.4、hex(*) 十六进制输出
hex(10) ----->#输出为十六进制字符串类型值
'0b1010'
1.2.4.5、oct()八进制输出
oct(10) ----->#输出为八进制字符串类型值
'0o12'
1.2.4.5.1、八进制运算
0o12 + 1 ---->十进制变为二进制后运算,结果为10进制
11
2、线性表原理和列表1
线性表:
线性表(简称表),是一种抽象的数学概念,是一组元素的序列的抽象,它由有穷个元素组成(0
个或任意个)
顺序表: 使用一大块连续的内存顺序存储表中的元素,这样实现的表称为顺序表,或称连续表
在顺序表中,元素的关系使用顺序表的存储顺序自然地表示
链接表: 在存储空间中将分散存储的元素链接起来,这种实现称为链接表,简称链表
列表如同地铁站排好的队伍,有序,可以插队、离队,可以索引。
链表如同操场上手拉手的小朋友,有序但排列随意。或者可以想象成一串带线的珠子,随意盘放在桌
上。也可以离队、插队,也可以索引。
对比体会一下,这两种数据结构的增删改查。
2.1、单向列表查询
image-20210826111032712
2.2、链接表
链接表: 在存储空间中将分散存储的元素链接起来,这种实现称为链接表,简称链表
image-20210826112211301
2.3、顺序表
顺序表:
使用一大块连续的内存顺序存储表中的元素,这样实现的表称为顺序表,或称连续表在顺序表中,元素的关系使用顺序表的存储顺序自然地表示
image-20210826113054870
2.4、列表list
一个排列整齐的队伍,Python采用顺序表实现
列表内的个体称作元素,由若干元素组成列表
元素可以是任意对象(数字、字符串、对象、列表等)
列表内元素有顺序,可以使用索引
线性的数据结构
使用 [ ] 表示
列表是可变的 ----->数据类型,可变也不可变
列表是非常重要的数据结构,对其内存结构和操作方法必须烂熟于心。
2.4.1、列表显示
[], list()
([], [])
[], list(), [1],[1,2],[1,2,'a','222',True,None,[3,4]]
([], [], [1], [1, 2], [1, 2, 'a', '222', True, None, [3, 4]])
list(range(5))
[0, 1, 2, 3, 4]
list([1,2,3])
[1, 2, 3]
l1 = list(range(5)) #index索引
l1 ----->赋值即定义
[0, 1, 2, 3, 4, 5]
l1[2] #len(l1-1) 正负索引不可以超界,超界报indexError
2
l1[-1],l1[-5] # [-len(l1), -1] ----->负索引,从后往前
(5, 1)
内建函数
len() ----->表示长度
l1 = [0,1,2,3,4,5]
len(l1)
6 长度为6
image-20210831141539035
2.4.2、初始化
list() -> new empty list
list(iterable) -> new list initialized from iterable's items
[]
列表不能一开始就定义大小
ls1 = []
ls2 = list()
ls3 = [2, 'ab', [3, 'abc'], (5, 30, 50)] # 列表是一个容器,元素可以是其它类型
ls4 = list(range(5)) # 非常常用的构造方式,将一个可迭代对象转换为一个列表
2.4.3、索引
索引,也叫下标
正索引:从左至右,从0开始,为列表中每一个元素编号
如果列表有元素,索引范围[0, 长度-1]
负索引:从右至左,从-1开始
如果列表有元素,索引范围[-长度, -1]
正、负索引不可以超界,否则引发异常IndexError
为了理解方便,可以认为列表是从左至右排列的,左边是头部,右边是尾部,左边是下界,右边是上界
列表通过索引访问,list[index] ,index就是索引,使用中括号访问
使用索引定位访问元素的时间复杂度为indexO(one),这是最快的方式,是列表最好的使用方式。
时间复杂度越小,效率越高
2.4.4、查询
index(value,[start,[stop]])
通过值value,从指定区间查找列表内的元素是否匹配
匹配第一个就立即返回索引
匹配不到,抛出异常ValueError
count(value)
返回列表中匹配value的次数
时间复杂度
index和count方法都是O(n)
随着列表数据规模的增大,而效率下降
如何返回列表元素的个数?如何遍历?如何设计高效?
len()
2.4.4.1、index()时间复杂度为大O(n)
index O(n) #随着规模n增加 耗时 增加
l1.index(4),l1.index(3)
(4, 3)
l1.index(4)
4
l2 = [0,1,2,1,3,4]
l2.index(1),l2.index(1,1),l2.index(1,2) 从1开始往后找1,从2开始往后找1
(1, 1, 3) 索引值
l2.index(1),l2.index(1,1),l2.index(1,2,-1)
(1, 1, 3) 索引值
l2.index(4,2),l2.index(4,3) 从2开始找4,从3开始找4
(5, 5) 索引值
index和 count 列表的方法效率如何?
count 遍历所有,O(n)
index O(n) #随着规模n增加 耗时 增加
len(l1) #效率高吗? 非常高 存我们班进入一个人计数器+1,离开一个计数器-1,列表是封装对象,这个对象有自己的元数据,长度时间复杂度为大O(1)
image-20210831150418421
2.4.4.2、len时间复杂度为大O(1)
len时间复杂度为大O(1),时间复杂度越小,效率越高
l2 = [0,1,2,3,4]
len(l2)
6
image-20210831152118272
2.4.4.3、count时间复杂度为大O(1)
count O(n) #随着规模n增加 耗时 增加
l2 = [0,1,2,3,4]
l2.count(5),l2.count(4),l2.count(1) 5的索引总数为0,4的索引总数为1,1的索引总数为2
(0, 1, 2)
count时间复杂度为大O(1)
image-20210831150933994
2.4.5、修改
索引定位元素,然后修改。注意索引不能超界
ls1 = [1,2,3,4]
ls1[2] = 200
3、列表2和内存原理
3.1、增加单个元素
append(object) -> None
列表尾部追加元素,返回None
返回None就意味着没有新的列表产生,就地修改
定位时间复杂度是O(1)
insert(index, object) -> None
在指定的索引index处插入元素object
返回None就意味着没有新的列表产生,就地修改
定位时间复杂度是O(1)
索引能超上下界吗?
超越上界,尾部追加
超越下界,头部追加
3.1.1、修改索引值
l2 = [0,1,2,1,3,4]
l2[-1] = 2
l2[-6] = [1,2] ------> 从后往前索引第6位,[1,2]作为一个整体作为一个元素
l2
[[1, 2], 1, 2, 1, 3, 2]
l2,len(l2) ------> l2的长度为6
([[1, 2], 1, 2, 1, 3, 2], 6)
len(l2)
6
l2[-1] = 2 -----> 修改从后往前的第一个值为2
l2
[[1, 2], 1, 2, 1, 3, 2]
image-20210831160941165
3.1.2、append末追加索引值,效率高
l3.append(None) #append 内部的最后加一个,效率好吗? 定位快,写操作比读操作慢。大O(1)
扩容问题: 另选地址,实现扩容
l3 = [1,2,3] ----->追加索引4
l3.append(4)
l3
[1, 2, 3, 4]
l3.append(6) ------->追加索引6
l3
[1, 2, 3, 4, 5, 6]
3.1.3、insert中插入索引值,效率低
insert效率高吗? 少用,效率低
l3 = [1,2,3,4,5]
l3.append(None)
l3
[1, 2, 3, 4, 5, None]
l3.insert(-3,9) ------>在倒数第三个中加9
l3
[1, 2, 3, 9, 4, 5, None]
l3.insert(4,10) ------>在正数第4个索引加10
l3
[1, 2, 3, 9, 10, 4, 5, None]
l3.insert(0,'begin') ------->在0索引处加一个'begin'
l3
['begin', 1, 2, 3, 4, 10, 5, 9, None, 8, 7]
l3.insert(-100,'left') # insert函数返回值为None。浙往往说明该方法是就地修改
l3
['left', 'begin', 1, 2, 3, 4, 10, 5, 9, None, 8, 7]
l3.insert(100,'right') ---->在索引100后面添加'right' #相当于append效率,效率不错
l3
['left', 'begin', 1, 2, 3, 4, 10, 5, 9, None, 8, 7, 'right']
#insert效率高吗? 一般来讲都不高insert(-1,xxx)中间插入,会引起其后所有的挪动
image-20210831170424824
image-20210831171000120
image-20210831171139948
3.2、增加多个元素
extend(iteratable) -> None
将可迭代对象的元素追加进来,返回None
就地修改,本列表自身扩展
+ -> list
连接操作,将两个列表连接起来,产生新的列表,原列表不变
本质上调用的是魔术方法__add__()方法
* -> list
重复操作,将本列表元素重复n次,返回新的列表
ls1 = [1] * 5
ls2 = [None] * 6
ls3 = [1,2] * 3
ls4 = [[1]] * 3
这个重复操作看似好用,如果原理掌握不好,但非常危险
x = [1] * 3
x[0] = 100
print(x) # 结果是什么
3.2.1、extend
l3.extend([1,2,3]) ---->同时追加多个元素,[1,2,3]
l3
['left', 'begin', 1, 2, 3, 4, 10, 5, 9, None, 8, 7, 'right', 1, 2, 3]
l3.extend(range(5,8)) ---->range(5,8)添加一个取值范围,前包后不包,添加5,6,7
l3
['left', 'begin', 1, 2, 3, 4, 10, 5, 9, None, 8, 7, 'right', 1, 2, 3, 5, 6, 7]
l2 + [5, 6, 7] ----->相加增加新的列表,但l2原来的值保持不变
[[1, 2], 1, 2, 1, 3, 2, 5, 6, 7]
l2
[[1, 2], 1, 2, 1, 3, 2]
l6
image-20210831172616552
image-20210831172849717
image-20210831173222665
3.2.2、将列表中的元素重复n回,装成一个新列表
l4 = [1,2] ----->将列表中的元素重复3回,装成一个新列表
l4*5
[1, 2, 1, 2, 1, 2, 1, 2, 1, 2]
[1]*3,[None]*3,[0]*5 ------>将列表中的元素重复指定回,装成一个元素
([1, 1, 1], [None, None, None], [0, 0, 0, 0, 0])
image-20210831232723795
3.2.3、修改索引值
l5 = [1]*3 ------>将1这个元素重复多回,放入一个列表里面
l5
[1,1,1]
l5[1] = 200 ------->修改l5中索引为1的改为200
l5 #[1,200,1]
[1, 200, 1]
l6 = [[1]]*3 ------->将[1]重复3次
l6
[[1], [1], [1]]
l6[1] = 300 ----->修改l6中索引1的元素为300
[[1], 300, [1]]
l6[0][0] = 500
[[500], 300, [500]]
l5 = [1]*3 #[1,1,1]
l5[1] = 200 # [1,200,1]
l6 = [[1]] *3 # [[1],[1],[1]] ------>类比
l6[1] =300 # [[1],300,[1]] ----- >索引1的位置被替换为300
l6[0][0] = 500 # [[500],300,[500]] l6[0] => [1][0] = 500 => [[500],300,[500]]
------>索引0所对应的值为[1]被替换等于[500],后面的[1]替换为[500]
print(l6)
[[500], 300, [500]]
300 'abc' 字面长量,简单类型,可以错误认为他们放在列表里面就是自己的值 ---->传值
l6[1] = 'absdsfcks' 复杂类型,都是引用类型,都是放地址,传地址 ---->传地址
在Python中一切皆对象,而对象都是引用类型,可以理解为一个地址指针指向这个对象。
但是,字面常量字符串、数值等表现却不像引用类型,暂时可以称为简单类型。
而列表、元组、字典,包括以后学习的类和实例都可以认为是引用类型。
你可以认为简单类型直接存在列表中,而引入类型只是把引用地址存在了列表中。
image-20210901154004723
image-20210902001525529
image-20210902002433163
4、列表3和深浅复制
4.1、删除三种方法
remove(value) -> None
从左至右查找第一个匹配value的值,找到就移除该元素,并返回None,否则ValueError
就地修改
效率? ----->删除0,判断0是否在再表中
pop([index]) -> item
不指定索引index,就从列表尾部弹出一个元素
指定索引index,就从索引处弹出一个元素,索引超界抛出IndexError错误
效率?指定索引的的时间复杂度?不指定索引呢?
clear() -> None
清除列表所有元素,剩下一个空列表
4.1.1、remove效率低
l6.remove(0) #效率高吗?非常低,找0 value得遍历。没找到还要抛异常ValueError,找到了,还要拿走,都会引起其后元素得挪动
l6
[[500], 300, [500]]
l6.remove(300)
l6
[[500], [500]]
remove: 用遍历来找值,大O(n),效率低下
image-20210902003703009
image-20210902094654911
4.1.2、pop效率高
l6
[[500], [500]]
l6.pop() ------->删除一个值[500]
[500]
l6.pop() ------->再删除一个值[500]
[500]
l6 ------->显示为空
[]
l3
['begin', 1, 2, 3, 4, 10, 5, 9, None, 8, 7, 'right', 1, 2, 3, 5, 6, 7]
l3.pop() ------->pop弹出索引中的7
7
l3 ------->显示删除结果中的7
['begin', 1, 2, 3, 4, 10, 5, 9, None, 8, 7, 'right', 1, 2, 3, 5, 6]
l3
['begin', 1, 2, 3, 4, 10, 5, 9, None, 8, 7, 'right', 1, 2, 3, 5, 6]
l3.pop() -------->从后往前弹出
6
l3.pop(0) -------->删除索引0对应的值begin
'begin'
l3
[1, 2, 3, 4, 10, 5, 9, None, 8, 7, 'right', 1, 2, 3, 5]
# 效率高吗?
# 一般不超界情况,比remove高,不用编历,给定index,定位数据快
# 如果不是末尾弹出的话,remove和pop从移除数据来讲都一样,拿走数据,后面的数据挪动
# 建议,列表来说,末尾移除倒数第一个元素,代价最小
列表使用:
append #追加、pop(-1) #删除元素、l1(index) #查看索引、len(l1) #索引长、l1[index] = 200, extend(range(5)) #同时追加多个元素
image-20210902095506088
image-20210902100529151
image-20210902101241065
4.1.3、clear 清除
清除列表所有元素,剩下一个空列表
clear 1000个元素,你说不要就不要了? 从慢的要死磁盘搬来了1000个数据
4.2、reverse反转效率低
reverse() -> None
将列表元素反转,返回None
就地修改
这个方法最好不用,可以倒着读取,都不要反转。
l3.reverse() ----->数据值反转 ----->第1种反转
for x in l3:
print(x)
5
3
2
1
right
7
8
None
9
5
10
4
3
2
1
l3
[5, 3, 2, 1, 'right', 7, 8, None, 9, 5, 10, 4, 3, 2, 1]
for index in range(1, len(l3)+1): len前包后不包,索引index取反 ----->第2种反转
print(l3[-index])
1
2
3
4
10
5
9
None
8
7
right
1
2
3
5
l3
[5, 3, 2, 1, 'right', 7, 8, None, 9, 5, 10, 4, 3, 2, 1]
for index in range(len(l3)-1,-1,-1): #索引到-1,每次递减1,输出索引 ----->第3种反转
print(l3[index])
1
2
3
4
10
5
9
None
8
7
right
1
2
3
5
image-20210902110144691
image-20210902111842619
image-20210902112437918
4.3、sort就地排序效率低
sort(key=None, reverse=False) -> None
对列表元素进行排序,就地修改,默认升序
reverse为True,反转,降序
key一个函数,指定key如何排序,lst.sort(key=function)
如果排序是必须的,那么排序。排序效率高吗?
l5 = [1,200,1]
l5
[1, 200, 1]
l5.sort() ------>就地排序
l5
[1, 1, 200]
l5.sort(reverse=True) ------>反转后面的值
l5
[200, 1, 1]
l3
[5, 3, 2, 1, 'right', 7, 8, None, 9, 5, 10, 4, 3, 2, 1]
l3.sort(key=str) #key 但不影响输出结果中的值
l3 ------>把里面所有元素变成str来比较,输出还是原值输出,不影响输出结果
排定座次,不影响输出结果
[1, 1, 10, 2, 2, 3, 3, 4, 5, 5, 7, 8, 9, None, 'right']
l3 #效率高吗? 不但遍历,而且大多数排序算法遍历n次-O(n*n)
# 冒泡法,插入排序,选择排序,堆排序,快速排序O 高效率O(1)
遍历时间复杂度是大O(n)
image-20210902132601356
image-20210902132911582
image-20210902133555766
4.4、in成员比较是否相等
'a' in ['a', 'b', 'c']
True
[3,4] in [1, 2, 3, [3,4]] ---->先比较类型,在比较类容,比顺序
True
for x in [1,2,3,4]:
pass
4.5、列表复制
列表复制
a = list(range(4))
b = list(range(4))
print(a == b)
c = a
c[2] = 10
print(a)
print(a == b) # 还相等吗?
print(a == c) # 相等吗?
4.5.1、列表复制示例
l7 = list(range(5)) ----->数据类型和数据都相等
l8 = list(range(5))
print(l7 == l8)
True
l7 = list(range(5))
l8 = list(range(5))
print(l7 == l8) # ==内容是否相等, 'a' == 1 首先比较类型,在比较内容,注意有序
x = l7
x[2] = 100
print(x == l7) #等吗? --时,先判断内存地址如果相等,直接返回True,如果不相等,再比较内容
True
True
l7 = list(range(5))
l8 = list(range(5))
print(l7 == l8)
x = l7
x[2] = 100
print(x == l7)
print(x == l8)
True
True
False
image-20210902172442039
image-20210902173201642
image-20210902211340195
4.5.2、列表的内存模型和深浅拷贝
# copy
l9 = list(range(5))
l10 = l9.copy() ----->复制,产生了一个人全新的副本
print(l9 == l10)
l9[1] = 100
print(l9 == l10)
print(l9,l10)
True
False
[0, 100, 2, 3, 4] [0, 1, 2, 3, 4]
l11 = [1,[2,3,4],[5]] # [1,A1,5] ------>浅拷贝,根本不跟踪到地址内部称为浅拷贝,影子拷贝
l12 = l11.copy() # [1,A1,5] ------>l11与l12打印出来的值一样,
print(1,l11 == l12)
l12[1][1] = 300
print(2,l11 == l12)
print(l11[1],id(l11[1]))
print(l12[1],id(l12[1]))
1 True
2 True
[2, 300, 4] 2127183061448 ------>地址相同,浅拷贝
[2, 300, 4] 2127183061448 ------>地址相同,浅拷贝
l11 = [1,[2,3,4],[5]] #[1,A1,5] [1,[2,3,4],5]
l12 = copy.deepcopy(l11) #[1,A2,5] [1,[2,3,4],5]
print(1,l11 == l12)
print(l11,l12)
l12[1][1] = 300
print(2,l11 == l12)
print(l11,l12)
print(l11[1],id(l11[1])) ------>地址不同,深拷贝
print(l12[1],id(l12[1])) ------>地址不同,深拷贝
1 True
[1, [2, 3, 4], [5]] [1, [2, 3, 4], [5]]
2 False
[1, [2, 3, 4], [5]] [1, [2, 300, 4], [5]]
[2, 3, 4] 2127182488968
[2, 300, 4] 2127183020232
大多使用的深拷贝
image-20210902212540032
image-20210902214009076
image-20210902214907111
4.6、Python内存管理(面试)
面试题。
变量无须事先声明,也不需要指定类型,这是动态语言的特性
变量只是一个标识符,指向一个对象,而这个对象被创建在内存"堆"中
Python编程中一般无须关心变量的存亡,一般也不用关心内存的管理
python使用引用计数记录所有对象的引用数。当对象引用数变为0,它就可以被 垃圾回收GC
计数增加:
赋值给其它变量就增加引用计数,例如x=3; y=x; z=[x, 1]
实参传参,如foo(y)
计数减少:
函数运行结束时,局部变量就会被自动销毁,对象引用计数减少
有关性能的时候,就需要考虑变量的引用问题,但是,到底该释放内存还是尽量不释放内存,看需求。
内存是宝贵的,因为它快。但再好的硬件资源,再多的机器,在高并发面前都嫌少。内存一定要
合理利用。
但是,数据搬到内存中不易,不要把大量数据好不容易搬到内存中,立刻就不要了。这非常没有
效率。
stop word
image-20210902225243475
4.6.1、引用计数的问题
标识垃圾的方法
引用计数是简单实现垃圾标记的办法。
引用计数可能出现循环引用,Python提供了gc模块,解决了这个问题。
import sys
#x = []
#print(sys.getrefcount(x))
#y = x
#print(sys.getrefcount(y))
#z = y
#print(sys.getrefcount(x))
z = 1 #字面常量
print(sys.getrefcount(z))
x = 1
y = 1
print(sys.getrefcount(x))
93
95
image-20210902231453433
5、随机数元组字符串
5.1、随机数
随机数
random模块
randint(a, b) 返回[a, b]之间的整数
randrange ([start,] stop [,step]) 从指定范围内,按指定基数递增的集合中获取一个随机数,基数
缺省值为1。 random.randrange(1,7,2)
choice(seq) 从非空序列的元素中随机挑选一个元素,比如random.choice(range(10)),从0到9中随机挑选一个整数。random.choice([1,3,5,7])
3.6开始提供choices,一次从样本中随机选择几个,可重复选择,可以指定权重
random.shuffle(list) ->None 就地打乱列表元素
sample(population, k) 从样本空间或总体(序列或者集合类型)中随机取出k个不同的元素,返回一个新的列表
random.sample(['a', 'b', 'c', 'd'], 2)
random.sample(['a', 'a'], 2) 会返回什么结果
每次从样本空间采样,在这一次中不可以重复抽取同一个元素
import random
for i in range(5):
print(random.randint(1,2)) ------>(1,2)随机的整数
2
1
1
2
2
image-20210903090634524
5.1.1、choices选择随机数
x = [1,2,3,4,5]
for i in range(5):
print(random.choice(x)) ---->拿5次数据,每次都从x中任意抽取一个元素
5
2
5
4
2
random.shuffle(x) ----->随机打乱数据
x
[1, 2, 4, 5, 3]
for i in range(5):
print(random.choices(x)) #取一下,等价为choice,返回值不同,默认k=1
[4]
[4]
[4]
[2]
[2]
for i in range(5):
print(random.choices(x,k=2)) #取一下,等价为choice,返回值不同,k=2可以重复的取2下
[5, 3]
[3, 4]
[5, 5]
[5, 5]
[3, 4]
for i in range(5):
print(random.choices([0,1],k=6)) ------>在[0,1]列表中,随机取6次
[1, 1, 1, 1, 1, 1]
[1, 0, 1, 0, 1, 0]
[1, 0, 0, 0, 0, 0]
[1, 0, 0, 0, 0, 1]
[1, 0, 1, 1, 1, 0]
for i in range(5):
print(random.choices([0,1],[10,1],k=6)) ---->在列表[0,1]按照10:1的量来取6个值
[0, 1, 0, 1, 0, 0]
[0, 0, 0, 0, 0, 0]
[0, 0, 0, 1, 1, 0]
[0, 0, 0, 0, 0, 0]
[0, 1, 0, 1, 1, 0]
image-20210903091247320
image-20210903093326675
image-20210903094037519
image-20210903095158516
image-20210903095505955
5.1.2、sample不重复拿数据
print(x)
print('***************')
for i in range(5):
print(random.sample(x, k=5)) --->不重复拿,每一个索引的元素拿一次
[1, 2, 4, 5, 3]
***************
[1, 4, 3, 2, 5]
[5, 4, 2, 1, 3]
[3, 5, 1, 4, 2]
[2, 1, 5, 4, 3]
[4, 3, 5, 1, 2]
x = [1,1,1,1,1]
print(x)
print('***************')
for i in range(5):
print(random.sample(x, k=5)) ----->分别在不同的索引上的1 ,k的值不能大于索引的值
[1, 1, 1, 1, 1]
***************
[1, 1, 1, 1, 1]
[1, 1, 1, 1, 1]
[1, 1, 1, 1, 1]
[1, 1, 1, 1, 1]
[1, 1, 1, 1, 1]
image-20210903100546396
image-20210903105730298
5.2、元组tuple
5.2.1、初始化
t1 = () # 空元组
t2 = (1,) # 必须有这个逗号
t3 = (1,) * 5
t4 = (1, 2, 3)
t5 = 1, 'a'
t6 = (1, 2, 3, 1, 2, 3)
t7 = tuple() # 空元组
t8 = tuple(range(5))
t9 = tuple([1,2,3])
5.2.2、元组的定义与使用
一个有序的元素组成的集合
使用小括号 ( ) 表示
元组是不可变对象
1,2
(1, 2)
(), tuple(),(1,) ---->两个空元组
((), (), (1,))
t1 = (), tuple(),(1,) ----->两个空元组,和有一个元素的元组,一个大元组的三个元素
t1
((), (), (1,))
t1 = (), tuple(),(1,)
t1
((), (), (1,))
t1, type(t1)
(((), (), (1,)), tuple) ----->元素类型为空元组
tuple(range(5)),tuple([1,2,5]),tuple(list(range(5)))
((0, 1, 2, 3, 4), (1, 2, 5), (0, 1, 2, 3, 4))
t2 = (0,1,2,3,4,5)
t2.index(1) , 1 in t2, 5 in t2 , 6 in t2 ,t2.count(2),len(t2) ------>1,2,5,6元素是否在t2中,in作为判断 , count(2)遍历元素2出现的次数为1, len(t2)元组的长度
(1, True, True, False, 1, 6)
t3 = (1,2)*3 ------>设置一个元组
t3
(1, 2, 1, 2, 1, 2)
for x in t3:
print(x)
1
2
1
2
1
2
t3[1] = 123 ------->次元组对象不可增删改,查可以
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-80-9f5045351df1> in <module>
----> 1 t3[1] = 123
TypeError: 'tuple' object does not support item assignment
t4 = ()
t4 = (1,[2,3,4],5) ------>地址为A1没变,A1对应的列表中的值发生改变
t4[1][1] = 300
t4
(1, [2, 300, 4], 5)
t5 = (1,(2,3,4),5) ------->此中间的(2,3,4)为元组所以,不能改元组
t5[1][1] = 200
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-87-a0d48b604633> in <module>
1 t5 = (1,(2,3,4),5)
----> 2 t5[1][1] = 200
TypeError: 'tuple' object does not support item assignment
t6 = ([1],)*3 ------>[1]*3 [1,1,1] #([1],[1],[1]) #(A1,A1,A1)
t6[0] = 'abc'
t6
([1], [1], [1])
t6[1][0] = 300
t6
([300], [300], [300])
image-20210903110346584
image-20210903110600225
image-20210903111224486
image-20210903112035840
image-20210903112615514
image-20210903140529584
image-20210903140712657
image-20210903142335137
image-20210903142821493
5.3、字符串
一个个字符组成的有序的序列,是字符的集合
使用单引号、双引号、三引号引住的字符序列
字符串是不可变对象,是字面常量
Python3起,字符串都是Unicode类型
5.3.1、初始化
s1 = 'string'
s2 = "string2"
s3 = '''this's a "String" '''
s4 = 'hello \n zhgedu.com'
s5 = r"hello \n zhgedu.com"
s6 = 'c:\windows\nt'
s7 = R"c:\windows\nt"
s8 = 'c:\windows\\nt'
name = 'tom'; age = 20 # python代码写在一行,使用分号隔开,不推荐
s9 = f'{name}, {age}' # 3.6支持f前缀
sql = """select * from user where name='tom' """
r前缀:所有字符都是本来的意思,没有转义
f前缀:3.6开始,使用变量插值
字符串不可修改
时间复杂度
find、index和count方法都是O(n)
随着字符串数据规模的增大,而效率下降
len(string)
返回字符串的长度,即字符的个数
5.3.2、字符串的使用
s1 = 'abc de f'
len(s1)
8
s2 = 'a\tb\nc' ------->转移过后只有5个字符
print(len(s2))
5
s3 = r'a\tb\nc' ------>添加r前缀后字符都是本来的意思,没有转意
print(len(s3))
7
for x in s1:
print(x,type(x))
a <class 'str'>
b <class 'str'>
c <class 'str'>
<class 'str'>
d <class 'str'>
e <class 'str'>
<class 'str'>
f <class 'str'>
'a' + 'b' ----->输出一个全新的对象
'ab'
s = 'a' ------>对象的地址发生改变
print(s, id(s))
s +='b' #s = s + 'b'
print(s,id(s))
s ='ab'
a 2012087083784
ab 2012166459776
s = 'a'
s1 = s *5
s1
'aaaaa'
''.join('abcd'), ",".join('abcd') ---->把空串与'abcd'拼接在一起,相当于间隔符
('abcd', 'a,b,c,d')
image-20210903145101380
image-20210903145409801
5.3.2.1、map拼接字符串
",".join(map(str,range(5))) #map(?,range(5)) ---->使用map拼接字符串
'0,1,2,3,4'
",".join(map(str,[1,'a',2])) ----->map拼接字符串
'1,a,2'
5.3.2.2、find找字符串中元素位置
s.find('t'),s.find('www'),s.find('edu'),s.find('com',7)
----->找不到返回-1,找到返回>=0的索引
(-1, 0, 7, 11)
s.rfind('t'),s.rfind('www'),s.rfind('edu'),s.rfind('com',8)
(-1, 0, 7, 11) ------>#大O(n) 遍历查找子串能少则少,rfind从左往右
s.index('www'),s.rfind('www') ,s.rindex('www')
(0, 0, 0) ------># O(n),两个测试'www'是否存在
s.count('www')
1 ------>'www'出现的次数
5.3.3、split分割字符串
"a \r\n\tb\tc\nd".split() #遍历字符串,用尽可能长的空白字符作为分隔符, 一刀两断
['a', 'b', 'c', 'd']
"a \r\n\tb\tc\r\nd".split('\r\n') ----->'\r\n'作为切割点
['a ', '\tb\tc', 'd']
"a \r\n\tb\tc\r\nd".split('\n') ----->'\n'作为切割点
['a \r', '\tb\tc\r', 'd']
s3 = ','.join('abcd') ----->maxsplit=2表示最多切两刀
s3.split()
['a,b,c,d']
s3.rsplit(',',maxsplit=2)
['a,b', 'c', 'd']
"\r\na \r\n\tb\nc\r\nd\r\n".splitlines() ----->#line? 有换行符的给切掉
['', 'a ', '\tb', 'c', 'd']
image-20210903160601410
5.3.3.1、partition切割符
s3 = ','.join('abcd')
s3.partition(',') #3元组,split(',',1)
('a', ',', 'b,c,d')
s3.rpartition(',') #rsplit(',',1)
('a,b,c', ',', 'd')
s3.partition('.') #3元组,split(',',1)
('a,b,c,d', '', '')
s3.rpartition('.') #rsplit(',',1)
('', '', 'a,b,c,d')
image-20210903164311896
5.3.4、replace替换
s3.replace(',','+++ ') #返回一个全新字符串,把,号替换成'+++'
'a+++b+++c+++d'
s4 = 'www.zhgedu.com' ------'ww'替换成一个w
print(s4.replace('w','w'))
print(s4.replace('ww','w'))
print(s4.replace('www','w'))
www.zhgedu.com
ww.zhgedu.com
w.zhgedu.com
image-20210903164728147
image-20210903165100321
5.3.5、strip移除
"\r\na \r\n\tb\nc\rd\r\n".strip('\nd\r') ----->移除\nd\r的值
'a \r\n\tb\nc'
"\r\na \r\n\tb\nc\rd\r\n".strip('a\n d\r')
'\tb\nc'
image-20210903165727701
image-20210906091426762
image-20210906091732527
5.3.6、首尾判断
endswith(suffix[, start[, end]]) -> bool
在指定的区间[start, end),字符串是否是suffix结尾
startswith(prefix[, start[, end]]) -> bool
在指定的区间[start, end),字符串是否是prefix开头
s3.startswith('a,b') ------>是不以'a,b'开头的
True
s3.startswith('a,b'),s3.endswith('d') ------->是不以'd'结尾的
(True, True)
cmd = input('>>') ------->移除两边空格,字符串转小写
if cmd.strip().lower()=='nginx': #Nginx,nginX
print('yes')
else:
print(cmd)
>>a
a
cmd = input('>>') ------->移除两边空格,字符串转小写
if cmd.strip().lower()=='nginx': #nginx,nginx
print('yes')
else:
print(cmd)
>>nginx
yes
cmd = input('>>') ------->移除两边空格,字符串转小写
if cmd.strip().lower()=='nginx': #nginx,nginx
print('yes')
else:
print(cmd)
>>NGinx
yes
image-20210906092459566
image-20210906092635564
image-20210906094320252
5.3.7、其它函数
其它函数
upper()大写
lower()小写
swapcase() 交换大小写
isalnum() -> bool 是否是字母和数字组成
isalpha() 是否是字母
isdecimal() 是否只包含十进制数字
isdigit() 是否全部数字(0~9)
isidentifier() 是不是字母和下划线开头,其他都是字母、数字、下划线
islower() 是否都是小写
isupper() 是否全部大写
isspace() 是否只包含空白字符
其他格式打印函数中文几乎不用,大家自行查看帮助
cmd = input('>>') ------>判断是否输入的数字或者字母
if cmd.strip().lower()=='nginx': #nginx,nginx
print('yes')
elif cmd.isalnum():
print(cmd, 'alnum')
else:
print(cmd)
>>aq1
aq1 alnum
cmd = input('>>') ------->输出第三个结果
if cmd.strip().lower()=='nginx': #nginx,nginx
print('yes')
elif cmd.isalnum():
print(cmd, 'alnum')
else:
print(cmd)
>>----
----
cmd = input('>>') ------->输出第一个结果
if cmd.strip().lower()=='nginx': #nginx,nginx
print('yes')
elif cmd.isalnum():
print(cmd, 'alnum')
else:
print(cmd)
>>nginx
yes
image-20210906110949033
image-20210906110903846
5.3.7.1、C风格printf-style
"I am %03d" % (20,)
'I like %s.' % 'Python'
"%3.2f%% 0x%x %#X" % (89.7654, 10, 256) # 宽度为3,小数点后2位
"I am %-5d" % (20,)
"%(host)s.%(domain)s" % {'domain':'magedu.com', 'host':'www'} # 靠名字对应
"I'm %s ." % (20)
"I'm 20 ."
"I'm %d years old." % (20)
"I'm 20 years old."
"I'm %s %s." % (20, 'years old')
"I'm 20 years old."
"%3.2f%%" % 20.236
'20.24%'
宽度为3,小数点后2位
"%3.2f%% %s %s" % (20.236,127,255)
'20.24% 127 255'
靠名字对应
"%(host)s.%(domain)s" % {'domain':'zhgedu.com','host':'www'}
'www.zhgedu.com'
image-20210906111039461
image-20210906113200890
image-20210906113806705
5.3.7.2、format函数
5.3.7.2.1、位置对应
位置对应
"I'm {} {}".format(20,'years old') ------>互为相同
"I'm 20 years old"
"I'm {1} {0}".format('years old',20) ------>互为相同,输入索引值
"I'm 20 years old"
位置或关键字对应
"{prefix} {1} {0}".format('years old',20,prefix="I'm") ------>互为相同
"I'm 20 years old"
"{} {} {}".format("I'm", 20, 'years old') ------>互为相同
"I'm 20 years old"
参数解构:
"I'm {} {}".format(*(20,'year lod'))
"I'm 20 year lod"
进制:
"{0},{0:d},{0:#b},{0:o},{0:#X}".format(31)
'31,31,0b11111,37,0X1F'
image-20210906114107947
image-20210906114705822
5.3.7.2.2、浮点数宽度
# 浮点数
print("{}".format(3**0.5)) # 1.7320508075688772
print("{:f}".format(3**0.5)) # 1.732051,精度默认6
print("{:10f}".format(3**0.5)) # 右对齐,宽度10
print("{:2}".format(102.231)) # 宽度为2数字
print("{:2}".format(1)) # 宽度为2数字
print("{:.2}".format(3**0.5)) # 1.7 2个数字
print("{:.2f}".format(3**0.5)) # 1.73 小数点后2位
print("{:3.2f}".format(3**0.5)) # 1.73 宽度为3,小数点后2位
print("{:20.3f}".format(0.2745)) # 0.275
print("{:3.3%}".format(1/3)) # 33.333%
# 注意宽度可以被撑破
"{:10f}".format(3**0.5) ----->右对齐,宽度为10
' 1.732051'
print("{:2}".format(102.231)) ------>宽度为2的数字
102.231
print("{:20}".format(102.231)) ------>宽度为20的数字
102.231
print("{:.2f}".format(3**0.5)) -------> 1.73小数点后2位
1.73
print("{:30.2f}".format(3**0.5)) -------> 1.73限制宽度为30,小数点后2位
1.73
print("{:30.2f}".format(0.2745)) -------> 1.73限制宽度为30,小数点后2位
0.27
print("{:30.3%}".format(1/3)) # 33.333% ------>小数点后三位,以%显示,宽度位30
33.333%
image-20210907110107336
image-20210907110322781
image-20210907111121643
5.3.7.2.3、对齐
# 对齐
print("{}*{}={}".format(5, 6, 5*6))
print("{}*{}={:2}".format(5, 6, 5*6))
print("{1}*{0}={2:3}".format(5, 6, 5*6))
print("{1}*{0}={2:0>3}".format(5, 6, 5*6))
print("{}*{}={:#<3}".format(4, 5, 20))
print("{:#^7}".format('*' * 3))
print("{}*{}={}".format(5, 6, 5*6))
5*6=30
print("{}*{}={:20}".format(5, 6, 5*6)) ------>设置宽度为20
5*6= 30
print("{1}*{0}={2:3}".format(5, 6, 5*6)) ------>宽度为3
6*5= 30
print("{1}*{0}={2:0>3}".format(5, 6, 5*6)) ----->右对齐
6*5=030
print("{1}*{0}={2:#<3}".format(5, 6, 5*6)) ------>左对齐
6*5=30#
print("{:#^7}".format('*' * 3)) ------>字符串 x 3 = *** ,要放到宽度为7的里面去,不足的地方补#号
##***##
print("{}*{}={:#<{}}".format(5, 6, 5*6,5))
5*6=30###
print("{}*{}={:#<{}}".format(5, 6, 5*6,2))
5*6=30
image-20210907135905777
image-20210907140008020
标签:02,None,python,image,列表,索引,l3,print,数据结构
From: https://www.cnblogs.com/zikang/p/17103894.html