IPython 增强了CPython
1.IPython中有很多内置的变量
_ : 表示前一次输出
__ : 表示倒数第二次输出
___ :表示倒数第三次输出
_dh:目录历史
_oh : 输出历史
2.shell命令
使用 !command 执行shell命令
3.魔术方法
%cd
%pwd:当前路径
%timeit:测试代码运行等待时间和效率
%%js:可以运行js脚本
集合Set
集合,简称集。由任意个元素构成的集体。高级语言都实现了这个非常重要的数据结构
类型。
Python中,他是可变的、无序的、不重复的元素的集合
无序代表不能进行进行索引访问
如何定义初始化集合: 1.s=set() 空集 2.s=set(range(5)) set('abcde') set(b'abc123') 这种都属于给集合中方可迭代对象,遍历一下过滤重复的元素放入集合 {0, 1, 2, 3, 4} {'d', 'e', 'a', 'c', 'b'} {97, 98, 99, 49, 50, 51} 对应输出这3个集合 3.s={1,2,range(0,5)} 输出 {1, 2, range(0, 5)} {'a',b'acb',(),'a','b'} 输出 {'a', 'b', (), b'acb'} 切记set有无序性和去重特性
4.列表list是不能哈希类型。集合中不能存放不可哈希类型的数据
不可哈希类型: list byterarray set 目前是这三个
集合的性质 1.去重:内容相等的和地址相等的都会去重保留一个 2.无序:每次输出顺序都不一样,所以不可索引 3.可哈希
对集合增加元素:
s={'a','b','c','d'}
print(s) 输出 {'c', 'a', 'b', 'd'}
s.add('e')
print(s) 输出 {'a', 'b', 'd', 'e', 'c'}
s.add('e')
如果加入的元素存在了,什么都不存在了
4.可迭代,就是能遍历一遍
5.批量增加
s={1,2,'a','b',(3,4)}
s.update(range(5))
输出 {'b', 1, 2, 'a', 0, (3, 4), 3, 4}
update()中放的是可迭代对象,有重复的就不要,放入不重复的元素
s.update(range(5),range(10,15),{1,'a','c'},['a','d'])
输出
{0, 1, 2, 3, 'a', (3, 4), 4, 10, 11, 12, 13, 14, 'd', 'b', 'c'}
update的时候,可以把其他的多个可迭代对象中的元素,挨着个的拿出来,拿出
来之后,依次的去塞入s集合当中但是要去重,这个是就地修改
s+{100,1,2} 集合不支持这样的加法
5.集合元素的删除
s.remove(14) #14是元素值,移除。
这个移除方法效率非常好,因为是非线性结构。这个移除看似是按值移除了
背后的原理是哈希值对应的问题。remove()效率极高 O(1).它背后不是按
照线性结构那种遍历。
s.discard('e') :e如果不存在集合中,也不会报错
有就移除,没有就不报错,效率极高O(1)
s.clear() :标记一下清零
s.pop() 随机的弹出一个值,一种无序的弹出。随机pop
集合的修改: 对于集合来说没有修改这一说,因为集合中存在的值,都是唯一的值。它这里的修改就是删除在新加元素
集合的查找: 非线性结构不可索引
集合的遍历问题: s={0, 1, 2, 3, 'a', (3, 4), 4, 10, 11, 12, 13, 14, 'd', 'b', 'c'}
for x in s:
print(x)
判断一个元素有没有在集合中,可以使用in成员操作符就能判断
0 in s 0是不是在s集合中 在的话 返回true
in 在列表中效率高吗?in 在set类型中效率高吗?
in 在列表中效率不高,因为需要从前向后遍历 时间复杂度为O(n)
in 在set中时间复杂度高,效率好 O(1)
说明,如果内存中有线程列表,你需要做的操作,里面用到了遍历,O(n) 数据
规模越大效率越低下。
列表这种数据结构不是让你快速检索的,除非规模很小,比如10个。
如果内存中有集合,不管数据规模多大,他的检索元素时间,不随着规模变化O(1)
效率极高 纳秒级别ns返回。
集合他的最典型应用,我们的值他是单值。我们单值还想去重,就放入集合。效率极高
爬虫的url 100万个url,你怎么知道那个被爬过,用集合存储。方便查询
有超大规模的集合就是用来给你判断的,你这个数据有没有在里面
只需要确定数据在或者不在请使用集合
hash内部原理
就是哈希计算哪里知识点 参考数据结构
请问:列表和set遍历,谁效率高?
都不高,都是O(n),尽量不要遍历。但凡是遍历都没有效率高的
遍历效率只和数据规模有关,规模越大效率越低
可哈希类型:
数值型 int float complex
布尔型 True False
字符串 String bytes
tuple
None
不可哈希类型:
list byterarray set
Set 集合运算:
只要是容器都可以使用in
集合的概念:
全集
子集
真子集和真超集
并集
交集
差集
并集运算:
a=[1,2,3]
b=[2,3,4,5]
a并b->a|b 输出
{1,2,3,4,5}
a.union(b) 等价于a|b
不做本地修改
交集运算:
空集表示: set()
a=[1,2,3]
b=[2,3,4,5]
a&b 交集输出 {2,3}
差集:A-B 和 B-A是不同的
A-B=A-(A&B)
a-b
字典Dict
Dict既Dictionary 在别的编程语言中也称为mapping映射。它为什么叫做映射呢?
是因为字典中每一个元素存储的都是一个键值对 key-value
key :唯一的、不重复的
字典是可变的、无序的、key不重复的
字典非常重要
1.字典的初始化 dict set list tuple 既是类名也是内建函数
dict():空字典、可变化
{} :空字典
d1={'a':1,'b':2}
输出为 {'a': 1, 'b': 2}
d2=dict(d1) dict(mapping) 这个就是mapping的含义
d2输出为 {'a': 1, 'b': 2}
dict(iterable) 使用可迭代对象进行初始化
d3=dict([ ('a',3),['b',100] ])
只能放二元结构
这个会输出:{'a': 3, 'b': 100}
由于列表和元组都是有序的,从里面拿出的第一个元素直接拿来做key,
第二个元素直接做 value
d3=dict([ ('a',3),['b',100],{3,100} ])
输出{'a': 3, 'b': 100, 3: 100}
这个{3,100}是一个集合,集合不一定有序。所以谁做key、谁做value是不一定的
d4 = dict(a=100,b=200,c=300)
输出 {'a': 100, 'b': 200, 'c': 300}
d5= dict([(1,100),[2,200],('a',111)])
输出 {1: 100, 2: 200, 'a': 111}
d5= dict([(1,100),[2,200],('a',111)],a=222)
输出
{1: 100, 2: 200, 'a': 222}
这个的意思就是a为222
d6=dict(d4,c=333,d=444)
输出 {'a': 100, 'b': 200, 'c': 333, 'd': 444}
后面会覆盖前面
直接用大括号构造字典 {'a': 100, 'b': 200, 'c': 333, 'd': 444}
对字典中的key要求,唯一且不重复
dict.fromkeys(range(5))
输出 {0: None, 1: None, 2: None, 3: None, 4: None}
创建了5个Key 0 1 2 3 4。它的每一个值都是None
dict.fromkeys(range(5),0)
输出 {0: 0, 1: 0, 2: 0, 3: 0, 4: 0}
vlaue值默认为0 这个参数的含义
d7=dict.fromkeys(range(5), [])
输出 {0: [], 1: [], 2: [], 3: [], 4: []}
缺省值合法就行
2.字典元素的访问 对于一个字典来讲,最重要的就是key了
d6=dict(d4,c=333,d=444)
输出 {'a': 100, 'b': 200, 'c': 333, 'd': 444}
d6['b']
输出 200 写key名称进行输出
d6['c']
输出 333
d6['e'] 没有这个key,会报错
d6.get('a')
输出 100
d6.get('e') 这里不会报错,即使这个key 'e'不存在
会返回一个None
d6.get('e',222)
'e'在字典中没有,就给222 进行输出,但是不会对原字典进行修改
if d6.get('e'):
pass 这里要注意None的问题
d6.setdefault('f')
输出 {'a': 100, 'b': 200, 'c': 333, 'd': 444, 'f': None}
没有'f'会进行添加,且value为 None
d6.setdefault('f',1234)
key不存在,使用缺省值凑成kv对,写入字典;key存在,相当于get
del d6['f']
删除 kv对
d6.setdefault('f',1234)
key不存在,使用缺省值凑成kv对,写入字典,同时返回这个写入的value值;
key存在相当于get
d6.setdefault('f',345)
这个语句的意思呢,先找'f'在不在字典里,'f'在取到1234。如果不在
把345和f做kv对匹配并且输出
{'a': 100, 'b': 200, 'c': 333, 'd': 444, 'f': 1234}
元素访问三种
d[key]
有keyError 问题
get(key[default])
setdefault(key[default])
3.对字典进行新增元素 d6['g']=[1,2,3] d6.update(d5) 用另一个字典更新 用mapping更新 有则覆盖,没有则新增,就地修改,以后面为准
封装和解构 t = 1,2 会直接把t封装成一个元组 等价于 t=(1,2). 这个就是封装的意思
t=(1,2)
x,y =t
x输出1 y输出2
它相当于把t这个元组, 拆开,分别于左边的标识符一一对应
x, y = 3, 4
x是3 y是4 输出
右边先封装成元组(3,4),然后为了赋值给x和y,解构后,依次对应标识符
a=100
b=200
交换两个值
t=a
a=b
b=t
a=100
b=200
a,b=b,a 交换 右边元组(200,100)
第一个给第一个,第二个值给第二个值
解构:
a,b=100,200
解构就是a=100 b=200 先把100 和200 封装为元组,在依次对应赋值
a,b = (3,4)
a,b = [5,6]
a,b = 'ab'
a='a' b='b'
a,b= b'xy'
a,b={7,8}
这个set集合,分别给a和b,不能确定谁给谁
a,b ={'m':9,'n':10} 字典
a='m' b='n' 字典第一层拿到的的key值
a,b= range(2)
输出 a=0 b=1
a,b= range(3)
左侧的标识符要和右边的值要一一对应
[a,b]=1,2
右侧要求是可迭代对象,这里会报错
(a,b)=[1,2]
a=1 b=2
a, *b=range(5)
b前面加 * 是什么意思呢? 尽可能收集数据放到一个列表中
输出 a=0 b=[1,2,3,4]
a, *b,c =range(5)
尽可能收集剩余数据放到一个列表中
输出 a=0 b=[1,2,3] c=5
a和c占用一个,其余给带星号的b,让他创建列表
*b=range(5)
这里会报错,不能这样使用
b=range(5) 加星号是没有意义的
a,*b,*c,d =range(10)
这个会输出什么?
a=0 d=9 *b 和*c输出什么? 这里会报错的。不知道*b拿多少
*c拿多少
a,*b,c=range(2)
a=0 b=[] c=1
剩余变量不能单独使用
*n=range(5) 这样写都是错误的
_, *a, _ = range(5)
_:输出 4
*a: 输出 [1,2,3]
_: 输出 4
下划线是同一个标识符,第一次赋值0,第二次赋值4 所以才才输出4
count=[0]*20
print(count)
输出 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
nums=[5,14,18,17,16,16,13,16,5] 7个元素
解析式和生成器表达式
列表解析式
nums=[]
for i in range(5):
nums.append(i+1)
print(nums)
输出 [1, 2, 3, 4, 5]
这段代码用来干什么的呢?
创建了一个全新的列表,初始化内容
这种东西就可以转为另一种形式,列表解析式、推导式
列表解析式、推导式
式的意思:表达式
[i+1 for i in range(5)] 生成一个空列表
从一个for循环中拿数据出来,这个数据拿出之后,对他加1,然后在加入了列表中
这个就是我们说的解析式的语法
立即生成一个新列表,填充内容
鼓励使用,代码执行效率高
列表初始化,尽量使用列表解析式表达
列表解析式是一种语法糖
编译器会优化
减少程序眼工作量
简化代码,增强可读性
nums=[]
for i in range(5):
nums.append((i+1)**2)
print(nums)
nums=[(i+1)**2 for i in range(5)]
print(nums)
[1, 4, 9, 16, 25]
[1, 4, 9, 16, 25]
求10以内的奇数
[i for i in range(10) if i%2==1]
[i for i in range(1,10,2)]
从range(1,10,2) 拿 i的值,一个个的加入列表中,加入的值放到第一个i中
实现20以内能被2整除或者能被3整除的数
print([i for i in range(20) if i%2==0 or i%3==0])
解析式当中不允许出现else和elif
[(x,y) for x in 'abcde' for y in range(3)]
#这个列表有几元素,元素类型是什么?
[('a', 0), ('a', 1), ('a', 2), ('b', 0), ('b', 1), ('b', 2),
('c', 0), ('c', 1), ('c', 2), ('d', 0), ('d', 1), ('d', 2),
('e', 0), ('e', 1), ('e', 2)]
生产了15个元组
for x in 'abcde'
for y in range(3)
(x,y)=a,0
a,1
a,2
依次类推 3X5=15 一共循环了15次
[[x, y] for x in 'abcde' for y in range(3)]
产生15个列表
[['a', 0], ['a', 1], ['a', 2], ['b', 0], ['b', 1], ['b', 2],
['c', 0], ['c', 1], ['c', 2], ['d', 0], ['d', 1], ['d', 2],
['e', 0], ['e', 1], ['e', 2] ]
这种简单的构建方式推荐使用
print([{x, y} for x in 'abcde' for y in range(3)])
该列表解析式有几个元素,类型是什么?
[{0, 'a'}, {1, 'a'}, {2, 'a'}, {0, 'b'}, {1, 'b'}, {2, 'b'},
{'c', 0}, {'c', 1}, {'c', 2}, {0, 'd'}, {1, 'd'}, {2, 'd'},
{'e', 0}, {'e', 1}, {'e', 2}]
15个元素,每个都不相同,集合是无序的、不能重复的
print([{x, y} for x in 'aaaaa' for y in [0,0,0]])
这个生成多少元素?
解析式里的集合是不进行去重的,去重是在集合内部去重,集合于集合之间不去重
[{0, 'a'}, {0, 'a'}, {0, 'a'}, {0, 'a'}, {0, 'a'}, {0, 'a'},
{0, 'a'}, {0, 'a'}, {0, 'a'}, {0, 'a'}, {0, 'a'}, {0, 'a'},
{0, 'a'}, {0, 'a'}, {0, 'a'}]
[(i,j) for i in range(7) if i>4 for j in range(20,25) if j>23]
for i in range(7)
if i > 4: 5 6 i的值大于4 才赋值给i
赋值给元组(i,)
for j in range(20,25)
if j >23 24 j大于24 才赋值给j
赋值给元组(,j)
输出这两个 [(5, 24), (6, 24)],看不懂进行转化
print([(i, j) for i in range(7) for j in range(20, 25) if j > 23]) 输出这个 [(0, 24), (1, 24), (2, 24), (3, 24), (4, 24), (5, 24), (6, 24)]
for i in range(7):
for j in range(20,25):
if i>4
if j>23
pass
一斜到底才能修改为解析式
[chr(random.randint(97, 123)) for i in range(10)]
生成器表达式
random.choices(string.ascii_lowercase,k=10)
random.sample(string.ascii_lowercase,k=10)
在某一个函数中,如果只需要一个参数,可迭代对象,如果要用生成器表达式
可以去除两边的小括号
print(["{:04}.{}".format( i, "".join( [chr(random.randint(97, 123)) for i in range(10)] 这个就是生成器表达式
)
) for i in range(1, 10)])
什么叫做生成器表达式? 把列表解析式中的中括号换成为小括号就行了
生成器表达式执行完,不会立即返回一个元组,返回的是一个生成器对象。
生成器对象是一个惰性的对象,比如range(),它返回的不是一个值,它返回一个
range对象,需要用for去驱动。
这个生成器对象也是需要这样的效果,需要驱动才能出元素。
惰性对象会做延迟计算,什么时候需要什么时候计算
生成器对象也是可迭代对象
生成器对象是迭代器,迭代器一定能迭代
可迭代对象最大 > 迭代器 > 生成器
a= (i+1 for i in range(5)) #生成器表达式
print(type(a)) #得到一个生成器对象,这个对象是惰性的
for x in a: #这里的a拿到的不是元组
print(x)
print('-'*20)
for x in a:
print(x)
#由生成器表达式得到这个生成器对象
#得到一个生成器对象,这个对象是惰性的
#这里的a拿到的不是元组,而是生成器类型
说白了现在,只拿到了地址,还不能知道具体内容
第二个for循环那个不会执行了,因为生成器对象,只能从头到尾遍历一次
next() 内建函数,作用就是拨动一下这个惰性对象。next函数只能用于迭代器中
b= range(4)
print(next(b))
这里会出现语法错误,range出来时多情求值对象,不是迭代器,是一个可迭代对象
c=list(range(5))
print(next(c)) C是列表,可迭代对象,不是惰性求值,也不是迭代器,更不是生
成器
如果迭代器已经遍历完,如果使用for就不遍历了
如果next,将抛出StopIteration 异常
生成器对象内部,有指针,指向当前位置,类似于链表
next 可以帮你判断这个是不是迭代器
一类是列表解析式 (顺序表)
一类是生成器解析式 (链表)
表达式不能过于复杂
解析式用于创建列表,或者生成器对象的。这个用处
预计算思想
懒惰计算思想
生成器用完就释放空间
str.join
" ".join() 括号里是可迭代对象
集合解析式 换成大括号语法同 生成器表达式和列表解析式
解析式都是立即返回对象
生成器表达式,返回一个生成器对象
{(x, y) for x in 'abcde' for y in range(3)}
{('e', 1), ('c', 1), ('b', 2), ('a', 2), ('c', 0), ('d', 1), ('d', 0), ('e', 0), ('b', 1), ('e', 2), ('a', 1), ('d', 2), ('b', 0), ('c', 2), ('a', 0)}
首先在集合内部构建元组,元组内容是由 x y 构成
字典解析式
{x: y for x in 'abc' for y in range(3)}
输出
{'a': 2, 'b': 2, 'c': 2}
{str(0x61 + x): x ** 2 for x in range(1, 4)}
输出
{'98': 1, '99': 4, '100': 9}
b c d
{chr(0x61 + x): x ** 2 for x in range(1, 4)}
输出
{'b': 1, 'c': 4, 'd': 9}
注意这两个区别
str(0x61 + x)
这个的意思就是把 98 转换为字符串‘98’ 做了强制类型转换
内建函数和迭代器
datetime 模块名
import datetime
datetime.datetime #类,抽象的概念,具体
#具体的时间,时间对象
#不带时区的时间
d1=datetime.datetime.now()
什么意思呢?
从一个(datetime)时间模块下的(datetime)时间类下的,调用类的方法now
从类的方法获取了一个具体的时间对象
print(d1) #缺省print打印是世界对象的一种字符串表达
d2 =datetime.datetime.utcnow()
utc 近似认为0时区时间
d3 = datetime.datetime(2018,8,8,10,20,30)
用类构造时间对象
带时区的时间如何获得
for index,element in enumerate(l1): #(数据,列表的元素 )
print(index,element)
enumerate 他会返回两个数据,下标和值 。
下标值由自己配,自己定index从几开始
迭代器:
iter([1,2,3]) 把非迭代器对象,转为迭代器
生成一个全新的迭代器对象
迭代器只能遍历一次,不能回头
zip()函数
list(zip(range(5), range(5),range(5) ))
输出
[(0, 0, 0), (1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4)]
每一个range()依次出一个数字构成 这5个元组
print(list(zip(range(5), range(5),range(2),range(5) )))
输出
[(0, 0, 0, 0), (1, 1, 1, 1)]
典型的木桶原理,迭代几个,看谁短
print( dict(zip('abcde',range(3)) ) )
输出
{'a': 0, 'b': 1, 'c': 2}
{k:v for k,v in zip('abcde',range(3))}
字典解析式构造