python-整理
逻辑运算符:与或非 and or not
and 如果前面的表达式等价为False,后面就没有必要计算了,这个逻辑表达式最终一定等价为False
or 如果前面的表达式等价为True,后面没有必要计算了,这个逻辑表达式最终一定等价为True
赋值运算符:先算右边后再赋值给左边变量
成员运算符: in 、not in
身份运算符: is 、is not
优先级:
算数运算符 > 位运算符 > 身份运算符 > 成员运算符 > 逻辑运算符
单目 > 双目
记不住用括号,长表达式多用括号,易懂易读
表达式Expression: 由数字、符号、括号、变量等的组合
算数表达式
逻辑表达式
赋值表达式 python中,赋值即定义,如果一个变量已经定义,赋值相当于重新定义
内存管理:
变量无须事先声明,也不需要指定类型,这是动态语言的特性
Python编程中一般无须关心变量的存亡,一般也不用关心内存的管理
Python使用引用计数记录所有对象的引用数,当对象引用数变为0,它就可以被垃圾回收GC
计数增加:赋值给其他变量就增加引用计数,例如x=3; y=x; z=[x,1] ;实参传参,如foo(y)
计数减少:函数运行结束时,局部变量就会被自动销毁,对象引用计数减少;变量被赋值给其他对象,例如:x=3; y=x; x=4;
有关性能的时候,就需要考虑变量的引用问题,但是该释放内存还是尽量不释放内存,看需求
for 循环中的 else 关键字指定循环结束时要执行的代码块
round(-2.5) 4舍 6入 5取偶
类型判断:
type(obj) 返回类型,而不是字符串
isinstance(obj, class_or_tuple) 返回布尔值
列表
一个列队,一个排列整齐的队伍
index(value,[start,[stop]])
L9.index(10) :查询到第一个后就不再遍历,括号中是value,随着列表中元素的增加,index 函数的效率下降,随着列表元素规模的增加,性能下降,有n元素个,时间复杂度,O(n)。匹配不到,抛出异常ValueError
count(value)
L1.count(100) :返回列表中匹配value的次数,全部遍历 O(n),随着列表数据规模的增大,而效率下降
len(list)
返回列表元素的个数
max(list)
返回列表元素最大值
min(list)
返回列表元素最小值
append(obj)
在列表末尾添加新的对象 就地修改
insert(index, obj)
将对象插入列表
extend()
L1.extend(rang(7,10)):在列表末尾一次性追加另一个序列中的多个值(用新列表扩展原来的列表)
[[1]] # [address:401] 401住着1
# 1 、‘abc’ 字面常量,称为简单类型
# [1] 复杂类型,应用类型
l1 = [[1]] * 5 # [ a401 , a401, a401, a401, a401] [[1],[1],[1],[1],[1]]
l1[0][0] = 100 # 修改的是 a401地址存储的值
l1
[[100], [100], [100], [100], [100]]
remove(value) -> None
从左至右查找第一个匹配value的值,找到就移除该元素,并返回None,否则ValuError,就地修改
pop([index]) -> item
不指定索引index,就从列表尾部弹出一个元素
指定索引index,就从索引处弹出一个元素,索引超界抛出IndexError错误
reverse()
反向列表中元素
sort( key=None, reverse=False)
对原列表进行排序
copy()
复制列表
clear() -> None
清除列表所有元素,剩下一个空列表
随机数:
random模块
randint(a,b) 返回[a,b]之间的整数
choice(seq) 从非空序列的元素中随机挑选一个元素,random.choice(range(10)) 从0到9中随机挑选一个整数。random.choice([1,3,5,7])
randrange([start,]stop[,step]) 从指定范围内,按指定基数递增的集合中获取一个随机数,基数缺省值为1。random.randrange(1,7,2)
random.shuffle(list) -> None 就地打乱列表元素
sample(population, k) 从样本看空间或总体(序列或者集合类型)中随机取出k个不同的元素,返回一个新的列表
三目运算符:
True if 条件 else False
a = 10
b = 15
if a > b:
a > b
else:
a < b
a > b if a > b else a < b
exp1 if contion else exp2
condition 是判断条件,exp1 和 exp2 是两个表达式。如果 condition 成立(结果为真),就执行 exp1,并把 exp1 的结果作为整个表达式的结果;如果 condition 不成立(结果为假),就执行 exp2,并把 exp2 的结果作为整个表达式的结果。
命名元组namedtuple
namedtuple(typename,field_names,verbose=False,rename=False)
命名元组,返回一个元组的之类,并定义了字段,field_names可以时空白符或逗号分割的字段的字符串,可以是字段的列表
同元组一样,命名元组的属性们的值不可变
from collections import namedtuple
Point = namedtuple('Point' , ['x','y'])
p1 = Point(4, 5) # 一旦赋值 ,不可修改
p1.x , p1.y # (4, 5)
Student = namedtuple('Student','name age')
tom = Student('tom',20)
jerry = Student('jerry',18)
tom.name , jerry.age # ('tom', 18)
class A :
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return "A (x={}, y={})".format(self.x , self.y)
a = A(5,6)
a.x , a.y # (5, 6)
字符串
一个个字符组成的有序的序列,是字符的集合
使用单引号、双引号、三引号引住的字符序列,是不可变对象
Python3起,字符串就是Unicode类型
0x31 ==> 0011 0001 49
0x41 ==> 0100 0001 65
0x61 ==> 0110 0001 97
a = 'abc'
a = f'{a}+++' # 差值 3.6版本以上
a ## 'abc+++'
range(5) # 惰性
range(0, 5)
list(range(5)) # 立即
[0, 1, 2, 3, 4]
map(str, range(5)) # 惰性,可迭代对象
<map at 0x14ab30181c8>
b = R'c:\windos\nt'
":".join(b) # 用 : 连接 b 中的每一个字符
'c:::\\:w:i:n:d:o:s:\\:n:t'
",".join(map(str, range(5))) # join后必须是str
'0,1,2,3,4'
rsplit(sep=None,maxsplit=-1) -> list of strings
从右向左开始切,但是输出的字符串字符不会反
sep指定分割字符串,缺省的情况下空白字符串作为分隔符
maxsplit指定分割的次数,-1表示遍历整个字符串
s1 = " I'm \ta super student."
s1.rsplit() # ["I'm", 'a', 'super', 'student.']
s1.rsplit('s') # [" I'm \ta ", 'uper ', 'tudent.']
s1.rsplit('s',maxsplit=1) # [" I'm \ta super ", 'tudent.']
partition(sep) -> (head,sep,tail)
从左至右,遇到分隔符就把字符串分割成两部分,返回头、分隔符、尾三部分的三元组;如果没有找到分隔符,就返回头、两个空元素的三元组
sep分割字符串必须指定
s1 = " I'm \ta super student."
s1.partition('s') # (" I'm \ta ", 's', 'uper student.')
s1.partition('stu') # (" I'm \ta super ", 'stu', 'dent.')
rpartition(sep) -> (head,sep,tail)
从右至左,遇到分隔符就把字符串分割成两部分,返回头、分隔符、尾三部分的三元组;如果没有找到分隔符,就返回头、两个空元素的三元组
splitlines()
"""\
a
b
c
""".splitlines() # 开头三引号后加反斜线 ,否则多切出一段
['a', 'b', 'c']
'a\n\nb\r\n\r\nc\rd\te'.splitlines()
('a', ' ', ' b')
'a b'.partition('t') # 特殊例子 切割符
('a b', '', '')
upper() 全大写
lower() 全小写
swapcase() 交换大小写
title() -> str 标题的每个单词都大写
capitalize() -> str 首个单词大写
center(width[,fillchar]) -> str width打印宽度 fillchar填充的字符
zfill(width) -> str width打印宽度,居右,左边用0填充
ljust(width[,fillchar]) -> str 左对齐
rjust(width[,fillchar]) -> str 右对齐
'abc'.upper().lower() # upper 统一转大写 lower 统一转小写
'abc'
"abC".swapcase() #大小写转换
'ABc'
str.upper('abc') , 'abc'.upper()
('ABC', 'ABC')
'user-agent'.capitalize() # 首字母大写
'User-agent'
'user-agent abc'.title()
'User-Agent Abc'
"abc".center(20,'0')
'00000000abc000000000'
"abc".ljust(20)
'abc '
"abc".rjust(20,"0")
'00000000000000000abc'
"abc".zfill(20)
'00000000000000000abc'
replace(old,new[,count]) -> str
字符串中找到匹配替换为新子串,返回新字符串,count表示替换几次,不指定就是替换全部
'www.magedu.com'.replace('w','p') # 'ppp.magedu.com'
'www.magedu.com'.replace('w','p',2) # 'ppw.magedu.com'
'x y'.replace(' ',' ') # 'x y'
strip([chars]) -> str
从字符串两端去除指定的字符集chars中的所有字符,如果chars没有指定,去除两端的空白字符
' \n a bc \t '.strip() # 默认拿掉字符串两端的所有空白字符
'a bc'
' \n a bc \t '.strip(' ')
'\n a bc \t'
' \f i am very very very sorry\t\r\n '.strip('\f\t\n\r yiar')
'm very very very so'
' \f i am very very very sorry\t\r\n '.strip('\f\t\n\ryiar')
' \x0c i am very very very sorry\t\r\n '
lstrip([chars]) -> str 从左边开始
rstrip([chars]) -> str 从右边开始
index(sub[,start[,end]]) -> int
在指定的区间[start,end), 从左至右查找子串sub。找到返回正索引,没找到抛出异常ValueError
rindex(sub[,start[,end]]) -> int
在指定的区间[start,end), 从左至右查找子串sub。找到返回正索引,没找到抛出异常ValueError
count(sub[,start[,end]]) -> int
在指定的区间[start,end), 从左至右统计子串sub出现的次数
len(string)
返回字符串的长度,即字符的个数
find、index和count方法都是O(n), 随着列表数据规模的增大,而效率下降
'\t a bc\r\ndef bc'.index('bc',5) #12 找不到时,返回ValueError
'\t a bc\r\ndef bc'.count('bc') #2 返回找到几个 没找到时返回0 不报错
'\t a bc\r\ndef bc'.find('abc') #-1 没有找到时,返回 小于零的数
endswith(suffix[,start[,end]]) -> bool
在指定的区间[star,end) ,字符串是否是suffix结尾
startswith(suffix[,start[,end]]) -> bool
在指定的区间[star,end) ,字符串是否是suffix开头
s = 'I am very very very very sorry'
s.startswith('very',5) # True
s.endswith('very',5,9) # True
s.endswith('sorry',5,100) #True
isalnum() -> bool 是否是字母和数字组成
isalpha() 是否是字母
isdecimal() 是否只包含十进制数字
isdigit() 是否全部数字(0~9)
isidentifier() 是不是字母和下划线开头,其他都是字母、数字、下划线
islower() 是否都是小写
isupper() 是否全部是大写
isspace() 是否只包含空白字符
字符串的格式化是一种拼接字符串输出样式的手段,更灵活方便
join 拼接只能使用分隔符,且要求被拼接的是可迭代对象且其元素是字符串
“+” 拼接字符串还算方便,但是非字符串需要先转换为字符串才能拼接
format函数格式字符串语法 ———— Python鼓励使用
“{}{xxx}”.format(*args, **kwargs) -> str
args是可变位置参数,是一个元组
kwargs是可变关键字参数,是一个元组
花括号表示占位符
{}表示按照顺序匹配位置参数,{n}表示取位置参数索引为n的值
{xxx}表示在关键字参数中搜索名称一致的
{{}}表示打印花括号
位置参数:
“{}:{}”.format(‘192.168.1.100’,8888),这就是按照位置顺序用位置参数替换前面的格式字符串的占位符
关键字参数或命名参数:
“{server}{1}{0}”.format(8888,’192.168.1.100′,server=’Web Server Info:’),位置参数按照序号匹配,关键字参数按照名词匹配
访问元素:
“{0[0]}.{0[1]}”.format((‘magedu’,’com’))
对象属性访问:
from collections import namedtuple
Point = namedtuple('Point' , 'x y')
p = Point(4, 5)
"{0.x},{0.y}".format(p) #'4,5'
'{0}'.format(list(range(5)))
'[0, 1, 2, 3, 4]'
'{0[4]}'.format(list(range(5)))
'4'
from collections import namedtuple
Student = namedtuple('Stu','name age')
tom = Student('tom', 20)
"{}".format(tom)
"Stu(name='tom', age=20)"
"{0.name} is {0.age}".format(tom) # 不使用
'tom is 20'
"{} is {}".format(tom.name, tom.age, tom)
'tom is 20'
ip = [192, 168, 1, 127]
"{} {} {} {}".format(*ip) # *ip 192, 168, 1, 127
'192 168 1 127'
"{:x} {{{}}} {:#x} {:#X}".format(*ip)
'c0 {168} 0x1 0X7F'
对齐:
'{0}*{1} = {2:<2}'.format(3,2,2*3) # '3*2 = 6 '
'{0}*{1} = {2:<02}'.format(3,2,2*3) # '3*2 = 60'
'{0}*{1} = {2:>02}'.format(3,2,2*3) # '3*2 = 06'
'{:^30}'.format('centered') # ' centered '
'{:*^30}'.format('centered') # '***********centered***********'
进制:
"int:{0:d}; hex:{0:x}; oct:{0:o}; bin:{0:b}".format(42)
# 'int:42; hex:2a; oct:52; bin:101010'
"int:{0:d}; hex:{0:#x}; oct:{0:#o}; bin:{0:#b}".format(42)
# 'int:42; hex:0x2a; oct:0o52; bin:0b101010'
octets = [192, 168, 0, 1]
'{:02X}{:02X}{:02X}{:02X}'.format(*octets)
# 'C0A80001'
浮点数
"{}".format(3**0.5) #'1.7320508075688772'
"{:f}".format(3**0.5) # '1.732051' 精度默认6
"{:10f}".format(3**0.5) #' 1.732051' 右对齐,宽度10
"{:2}".format(102.231) # '102.231' 宽度为2数字
"{:.2}".format(3**0.5) # '1.7' 2个数字
"{:.2f}".format(3**0.5) #'1.73' 小数点后2位
"{:3.2f}".format(3**0.5) # '1.73' 宽度为3,小数点后2位
"{:20.3f}".format(0.2745) # ' 0.275' 宽度为20,小数点后3位
"{:3.3%}".format(1/3) #'33.333%'
x = 2 ** 0.5
"{}".format(x)
'1.4142135623730951'
"{:.3f}".format(x)
'1.414'
"{:^20.2}".format(x)
' 1.4 '
"{:*^20.2}".format(x)
'********1.4*********'
"{:4.4%}".format(x)
'141.4214%'
"{:e}".format(x)
'1.414214e+00'
"{:2}".format(x)
'1.4142135623730951'
"{:.2}".format(x)
'1.4'
Python3引入两个新类型 bytes bytearray
bytes 不可变字节序列
bytearray 字节数组 可变
字符串与bytes
字符串是字符组成的有序序列,字符可以使用编码来理解
bytes是字节组成的有序的不可变序列
bytearray是字节组成的有序的可变序列
编码与解码
字符串按照不同的字符集编码encode返回字节序列bytes
encode(encoding=’utf-8′,errors=’strict’) -> bytes
字节序列按照不同的字符集编码encode返回字符串
bytes.decde(encoding=’utf-8′,errors=’strict’) -> str
bytearray.decde(encoding=’utf-8′,errors=’strict’) -> str
ASCII (American Standard Code for Information Interchange, 美国信息交换标准代码) 是基于拉丁字母的一套单字节编码系统
\t 0x09
\r 0x0d
\n 0x0a
0~9 0x30~0x39
A~Z 0x41~0x5A
a~z 0x61~0x7A
a = '\x0d\x0a\x09'
a
'\r\n\t'
x = 'abc'
y = x.encode() # x必须是字符串类型
x,y
('abc', b'abc')
y.decode() # bytes类型对象.decode() 二进制 => str
'abc'
hex(123)
'0x7b'
utf-8 中文大多数都是3字节
utf-8 是一种多字节编码,适合于网络传输,所以在网络中大量的使用
unicode是双字节编码
utf-8和GBK都兼容ascii码
字符串’1′,可以写成 x = ‘1’ ,y =’\x31′
‘\x09’ 就是 ‘\t’
‘\x0d\x0a’ 就是’\r\n’, 但是’\x0d0a’表示’\r0a’,所以得一个一个字节描述
bytes() 空bytes
bytes(int) 指定字节的bytes,被0填充
bytes(iterable_of_ints) -> bytes[0,255]的int组成的可迭代对象
bytes(string,encoding[,errors]) -> bytes 等价于string.encode()
bytes(bytes_or_buffer) -> immutable copy of bytes_or_buffer 从一个字节序列或者buffer复制出一个新的不可变的bytes对象
使用b前缀定义,只允许基本ASCII使用字符形式 b’abc9’,使用16进制表示 b”\x41\x61″
和str类型类似,都是不可变类型,所以方法很多都一样。只不过bytes的方法,输入的是bytes,输出的是bytes
b’abcdef’.replace(b’f’,b’k’) #b’abcdek’
b’abc’.find(b’b’) #1
类方法 bytes.fromhex(string) ,string必须是2个字符的16进制的形式,’6161 6a 6b’, 空格将被忽略
bytes.fromhex(‘6162 09 6a 6b00′) # b’ab\tjk\x00’
hex() 返回16进制表示的字符串
‘abc’.encode() # b’abc’
‘abc’.encode().hex() #’ 616263′
索引 b’abcdef'[2] # 99 返回该字节对应的数,int类型 , ‘c’ => \0x63 => 99
bytearray和bytes类型的方法相同
bytearray(b’abcdef’).replace(b’f’,b’k’) # bytearray(b’abcdek’)
bytearray(b’abc’).find(b’b’) # 1
类方法 bytearray.fromhex(string)
string必须是2个字符的16进制的形式,’6162 6a 6′ ,空格将被忽略
bytearray.fromhex(‘6162 09 6a 6b00′) #bytearray(b’ab\tjk\x00’)
hex() 返回16进制表示的字符串
bytearray(‘abc’.encode()) # bytearray(b’abc’)
bytearray(‘abc’.encode()).hex() #’616263′
索引 bytearray(b’abcdef’)[2] # 99 返回该字节对应的数,int类型
append(int) 尾部追加一个元素
insert(index, int) 在指定索引位置插入元素
extend(iterable_of_ints) 将一个可迭代的整数集合追加到当前byterray
pop(index=-1) 从指定索引上移除元素,默认从尾部移除
remove(value) 找到第一个value移除,找不到抛ValueError异常
注意:上述方法若需要使用int类型,值在[0,255]
clear() 清空bytearray
reverse() 翻转bytearray,就地修改
b = bytearray()
b.append(97) # bytearray(b'a')
b.append(99) # bytearray(b'ac')
b.insert(1,98) # bytearray(b'abc')
b.extend([65,66,67]) # bytearray(b'abcABC')
b.remove(66) # bytearray(b'abcAC')
b.pop() # 67 bytearray(b'abcA')
b.reverse() # bytearray(b'Acba')
b.clear() # bytearray(b'')
int和bytes
int.from_bytes(bytes,byteorder) 将一个字节数组表示成整数
int.to_bytes(length,byteorder) bytearray字节序 将一个整数表达成一个指定长度的字节数组
i = int.from_bytes(b'abc','big')
print(i, hex(i)) # 6382179 0x616263
print(i.to_bytes(3,'big')) # b'abc'
b1 = bytearray()
b1.append(97) # bytearray(b'a')
b1.extend(range(98,100)) # bytearray(b'abc')
线性结构特征:
可迭代 for … in
有长度,通过len(x)获取,容器
通过整数下标可以访问元素。正索引、负索引、可以切片
sequence[start:stop]
sequence[start:stop:step]
通过给定的索引区间获得线性结构的一部分数据
start、stop、step为整数,可以是正整数、负整数、零
start为0时,可以省略
stop为末尾时,可以省略
step为1时,可以省略
切片时,索引超过上界(右边界),就取到末尾;超过下界(左边界),取到开头
在序列上使用切片[start:stop],子区间索引范围[start:stop],相当于从start开始指向stop的方向上获取数据
默认step为1,表示向右;步长为负数,表示向左
如果子区间方向和步长方向不一致,直接返回当前类型的”空对象”
如果子区间方向和步长方向一致,则从起点间隔步长取值
b = a[i:j]
表示复制a[i]到a[j-1],以生成新的list对象
a = [0,1,2,3,4,5,6,7,8,9]
b = a[1:3] # [1,2]
当i,j都缺省时,a[:] 就相当于完整复制一份a
b = a[i:j:s]
表示:i,j与上面的一样,但s表示步进,默认为1
所以 a[i:j:1] 相当于 a[i:j]
当s<0时,i 缺省时,默认为-1. j 缺省时,默认为-len(a)-1
所以a[::-1]相当于 a[-1:-len(a)-1:-1],也就是从最后一个元素到第一个元素复制一遍,即倒序
a='abcdef'
b=a[::-1]
print(b) #fedcba
c=a[::-2]
print(c) # fdb
封装(装箱)
将多个值使用逗号分割,组合在一起,本质上,返回一个元组,只是省掉了小括号
python特有语法,被很多语言学习和借鉴
t1 = (1, 2)
t2 = 1, 2
type(t1) # tuple
type(t2) # tuple
nums = [1,2]
nums[1],nums[0] = nums[0],nums[1]
print(nums) # [2, 1]
a, *b = 1,2,3,4,5
a, b # (1, [2, 3, 4, 5])
a, *b ='xyz'
a, b # ('x', ['y', 'z'])
x, [a, b], z = 1, [2, (3, 5)], (2,6)
x, a, b, z # (1, 2, (3, 5), (2, 6))
* 代表零个或任意个
for x,*y in ((1,), [2,3], (4,5,7), [6]):
print(x,y)
1 []
2 [3]
4 [5, 7]
6 []
解构
a,*b = (1,2,3) # (1, [2, 3])
a,b = (1,2,3) # ValueError: too many values to unpack (expected 2)
a,b = {'a':10, 'b':20} #非线性解构也可以解构 解构出key
使用 *变量名接收,但不能单独使用,也不能出现多个
被 *变量名 收集后组成一个列表
head, *mid, tail = range(6)
head, mid, tail # (0, [1, 2, 3, 4], 5)
丢弃变量
这是一个惯例,一个不成文的约定,不是标准
如果不关系一个变量,就可以定义该变量名为 ““
““是一个合法的标识符,也可以作为一个有效的变量使用,但是定义成下划线就是希望不要被使用,除非你明确的知道这个数据需要使用
lst = [9,8,7,20]
first, *second = lst
head, *_, tail = lst
print(head) # 9
print(tail) # 20
print(_) # [8, 7]
“_” 是合法的表示符,看到下划线就知道这个变量就是不想被使用
_, *_, _, c = range(5)
c # 4
““这个变量本身无任何语义,没有任何可读性,所以不是用来给人使用的
Python中很多库,都使用这个变量,使用十分广泛。请不要再不明确作用域的情况下,使用”“导致和库中”_”冲突
集合set
collection 翻译为集合类型或容器,是一个大概念
set 可变的、无序的、不重复的元素的集合
set() -> new empty set object
set(iterable) -> new set object
s1 = set() # set() 空集合
s2 = set(range(5)) # {0, 1, 2, 3, 4}
s3 = set(list(range(5))) # {0, 1, 2, 3, 4}
s4 = {} # {}
s5 = {9,10,11} # {9, 10, 11}
s6 = {(1,2), 3, 'a'} # {(1, 2), 3, 'a'}
s7 = {[1], (1,), 1} # unhashable type: 'list'
set定义时不能出现 list bytearray dict set 类型 (不可hash)
set的元素要求必须可以hash
元素不可以索引
set可以迭代
set增加
add(elem) 增加一个元素到set中,如果元素存在,什么都不做
update(*others) 合并其他元素到set集合中来,参数others必须是可迭代对象,就地修改
s1 = set(range(5)) # {0, 1, 2, 3, 4}
s1.add(4) # {0, 1, 2, 3, 4}
s1.add(5) # {0, 1, 2, 3, 4, 5}
s1.add((1,2)) # {(1, 2), 0, 1, 2, 3, 4, 5}
s1.add((2,1)) # {(1, 2), (2, 1), 0, 1, 2, 3, 4, 5}
s1.add((1,2)) # {(1, 2), (2, 1), 0, 1, 2, 3, 4, 5}
t2 = 'a','b','c'
s1.add(t2) # {('a', 'b', 'c'), (1, 2), (2, 1), 0, 1, 2, 3, 4, 5}
s2 = set(range(8)) # {0, 1, 2, 3, 4, 5, 6, 7}
s1.update(s2) # {('a', 'b', 'c'), (1, 2), (2, 1), 0, 1, 2, 3, 4, 5, 6, 7}
s1.update(s2, range(10,15)) # {('a', 'b', 'c'), (1, 2), (2, 1), 0, 1, 10, 11, 12, 13, 14, 2, 3, 4, 5, 6, 7}
s3 = set(list(range(100,105))) # {100, 101, 102, 103, 104}
s2 + s3 # unsupported operand type(s) for +: 'set' and 'set'
set 不可以相加,加的概念是合并
set删除
remove(elem) 从set中移除一个元素,元素不存在,抛出异常KeyError异常
discard(elem) 从set中移除一个元素,元素不存在,什么都不做
pop() -> item 移除并返回任意的元素
clear() 移除所有元素
s3 = set(list(range(100,105))) # {100, 101, 102, 103, 104}
s3.remove(102) # {100, 101, 103, 104}
s3.remove(105) # KeyError: 105
s3.discard(105) # 不出错版本的remove
s3 # {100, 101, 103, 104}
s3.pop() # 100 随机弹出
s3 # {101, 103, 104}
set 是非线性结构,无法索引,可以迭代所有元素
in 和 not in 判断元素是否在set中
list和set的效率比较
l1 = list(range(100))
l2 = list(range(1000000))
%timeit (-1 in l1)
968 ns ± 9.55 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
%timeit (-1 in l2)
9.45 ms ± 67 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
l1 = set(list(range(100)))
l2 = set(list(range(1000000)))
%timeit (-1 in l1)
42.1 ns ± 1.78 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
%timeit (-1 in l2)
40.8 ns ± 1.77 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
线性结构的查询时间复杂度是O(n), 即随着数据规模的增大而增加耗时
set、dict等结构,内部使用hash值作为key,时间复杂度可以做到O(1),查询时间和数据规模无关
可hash
数值型 int float complex
布尔型 True False
字符串 string bytes
tuple
None
以上都是不可变类型,成为可哈希类型,hashable
set的元素要求必须可以hash
解释器每次运行拿到的hash值不一样,去重时,hash值一样,就不添加
集合运算
并集:将两个集合A和B的所有元素合并到一起,组成的集合称作集合A与集合B的并集
union(*others) 返回和多个集合合并后的新的集合
| 运算符重载 等同union
update(*others) 和多个集合合并,就地修改
|= 等同update
交集:集合A和集合B,由所有属于A且属于B的元素组成的集合
intersection(*others) 返回和多个集合的交集
& 等同 intersection
intersection_update(*others) 获取和多个集合的交集并就地修改
&= 等同intersection_update
差集:集合A和集合B,由所有属于A且不属于B的元素组成的集合
difference(*others) 返回和多个集合的差集
-
等同difference
difference_update(*others) 获取和多个集合的差集并就地修改
-= 等同difference_update
对称差集:集合A和集合B,由所有不属于A和B的交集元素组成的集合,记作(A-B)∩(B-A)
symmetric_differece(other) 返回和另一个集合的对称差集
^ 等同symmetric_differece
symmetric_differece_update(other) 获取和另一个集合的对称参集并就地修改
^= 等同symmetric_differece_update
字典dict
key-value键值对的数据集合 可变的、无序的、key不重复
d = dict() 或者 d = {}
dict(**kwargs) 使用 name=value对 初始化一个字典
dict(iterable, **kwargs)使用可迭代对象和 name=value对 构造字典,不过可迭代对象的元素必须是一个二元结构 d = dict(((1,’a’),(2,’b’))) d = dict([(1,’a’),(2,’b’)], c=300)
dict(mapping, **kwargs) 使用一个字典构建另一个字典
d = {‘a’:10, ‘b’:20, ‘c’:None, ‘d’:[1,2,3]}
类方法 dict.fromkeys(iterable, value) d = dict.fromkeys(range(5)) d = dict.fromkeys(range(5), 0)
d[key] 返回key对应的值value, key不存在抛出KeyError异常
get(key[, default]) 返回key对应的值value, key不存在返回缺省值,如果没有设置缺省值就返回None d1.get(4,’kong’)
setdefault(key[, default]) 返回key对应的值value; key不存在, 添加kv对, value设置为default, 并返回default, 如果default没有设置, 缺省为None d1.setdefault(2,’ef’)
d[key] = value 将key对应的值修改为value, key不存在添加新的kv对
update([other]) -> None 使用另一个字典的kv对更新本字典,key不存在就添加,key存在则覆盖已经存在的key对应的值,就地修改 d2.update({5:’ad’}) d2.update(((‘red’,3),)) d2.update(red=1)
pop(key[, default]) key存在,移除它,并返回它的value; key不存在,返回给定的default; default未设置,key不存在抛出KeyError异常
popitem() 移除并返回一个任意的键值对,字典为empty,抛出异常KeyError异常
clear() 清空字典
a = True
b = [1]
d = {'a':1, 'b':b, 'c':[1, 3, 5]}
a, b, d # (True, [1], {'a': 1, 'b': [1], 'c': [1, 3, 5]})
del d['c'] # (True, [1], {'a': 1, 'b': [1]})
看着像删除了一个对象,本质上减少了一个对象的引用,del实际上删除的是名称,而不是对象
字典遍历
for … in dict 遍历item,即kv对 d.keys() d.values()
for item in d.items():
pirint(item)
for item in d.items():
pirint(item[0], item[1])
for k,v in d.items():
pirint(k, v)
for k,_ in d.items():
pirint(k)
for _,v in d.items():
pirint(v)
for 里面允许修改值,但长度不能变化。使用到keys values items ,就不能进行kv对增加和kv对减少
while 里可以删除,修改字典长度。因为没有用到keys values items 方法
Python3中,keys、 values、 items方法返回一个类似一个生成器的可迭代对象,不会把函数的返回结果复制到内存中
Dictionary view对象,可以使用len()、 iter()、 in 操作
字典的entry的动态的视图,字典变化,视图将反映出这些变化
keys返回一个类set对象,也就是可以看做一个set集合。如果values都可以hash,那么items也可以看做是类set对象
字典的key
key的要求和set的元素要求一致,set的元素可以就是看做key,set可以看做dict的简化版
hashable可哈希才可以作为key,可以使用hash()测试
dict从3.6 按录入序记录,但实际hash值千差万别