1. typing模块
# typing模块:提供了Generator(生成器类型),Iterable(可迭代类型),Iterator(迭代器类型)三种数据类型,限制函数
def self_add(x:int,y:int):
return x + y
res = self_add(10,20)
print(res) # 30
from typing import Generator,Iterable,Iterator
# 参数的数据类型 返回值的数据类型
def func(i:int,f:float,b:bool,lt:list,tup:tuple,dic:dict,g:Generator) -> tuple:
lis = [i,f,b,lt,tup,dic]
return tuple(lis)
'''
在传入参数时通过"参数名:类型"的形式声明参数的类型;
返回结果通过"-> 结果类型"的形式声明结果的类型。
在调用的时候如果参数的类型不正确pycharm会有提醒,但不会影响程序的运行。
对于如list列表等,还可以规定得更加具体一些,如:"-> List[str]”,规定返回的是列表,并且元素是字符串
'''
# i, f, b, lt, tup, dic = func(1,2,3,4,5,6) # 不错误,只是不规范
def ger():
yield
res = func(1,2,True,[1,2],(1,2),{'a':1},ger())
print(res) # (1, 2, True, [1, 2], (1, 2), {'a': 1})
2. re模块
# re模块:从字符串里找特定的字符串,正则表达式
# re基本语法:
import re
s = '小葡萄吃葡萄被葡萄酸死了,小葡萄吃葡萄被葡萄酸死了'
# 0 1 2 3 4 5 6 7 8 9 10
print(s[1:3],s[7:9]) # 葡萄 葡萄
res = re.findall('小',s)
print(res) # ['小', '小']
# ^:开头
print(re.findall('^小葡萄',s)) # ['小葡萄']
# $:结尾
print(re.findall('死了$',s)) # ['死了']
# []:匹配中间的字符,只要单个字符
s = 'acefghjkacefsdfsdf'
print(re.findall('[acef]',s)) # 只要单个字符
# ['a', 'c', 'e', 'f', 'a', 'c', 'e', 'f', 'f', 'f']
# []+^联用:^对[]内的元素取反
print(re.findall('[^acef]',s)) # ['g', 'h', 'j', 'k', 's', 'd', 's', 'd']
# .:任意字符(除了\n)
s = 'abacadaeaf'
print(re.findall('a..',s)) # ['aba', 'ada']
s = 'abaacaaaaa'
# *:前面的字符0-无穷个
print(re.findall('a*',s)) # ['a', '', 'aa', '', 'aaaaa', '']
# +:前面的字符1-无穷个
print(re.findall('a+',s)) # ['a', 'aa', 'aaaaa']
# ?:前面的字符0-1个
print(re.findall('a?',s)) # ['a', '', 'a', 'a', '', 'a', 'a', 'a', 'a', 'a', '']
# {m}:前面的字符m个
print(re.findall('a{5}',s)) # ['aaaaa']
# {n,m}:前面的字符2-3个
print(re.findall('a{2,5}',s)) # ['aa', 'aaaaa']
# \d:数字
s = 's 1 s+\n=$\t2_s 3'
print(re.findall('\d',s)) # ['1', '2', '3']
# \D: 非数字
print(re.findall('\D',s)) # ['s', ' ', ' ', 's', '+', '\n', '=', '$', '\t', '_', 's', ' ']
# \w: 数字/字母/下划线
print(re.findall('\w',s)) # ['s', '1', 's', '2', '_', 's', '3']
# \W: 非数字/字母/下划线
print(re.findall('\W',s)) # [' ', ' ', '+', '\n', '=', '$', '\t', ' ']
# \s: 空格/\t/\n
print(re.findall('\s',s)) # [' ', ' ', '\n', '\t', ' ']
# \S: 非空格/\t/\n
print(re.findall('\S',s)) # ['s', '1', 's', '+', '=', '$', '2', '_', 's', '3']
# \:取消意义
s = 'aba\d'
print(re.findall(r'a\\d',s)) # ['a\\d']
# .*:贪婪模式(最大化),找到继续找,让结果最大化
s = 'abbbcabc'
print(re.findall('a.*c',s)) # ['abbbcabc']
# .*?: 非贪婪模式(最小化),找到就马上停止
print(re.findall('a.*?c',s)) # ['abbbc', 'abc']
# (): 只要括号内的
s = 'abacad'
print(re.findall('a(.)',s)) # ['b', 'c', 'd']
# A|B: A和B都要
s = 'abacad'
print(re.findall('a|b',s)) # ['a', 'b', 'a', 'a']
# re模块的方法
# re.compile
'''
修饰符 描述
re.I 使匹配对大小写不敏感
re.L 做本地化识别(locale-aware)匹配
re.M 多行匹配,影响 ^ 和 $
re.S 使 . 匹配包括换行在内的所有字符
re.U 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B.
re.X 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。
'''
s = 'abc123\ndef456'
print(re.findall('\d+',s)) # ['123', '456']
com = re.compile('\d+')
par = '\d+'
com = re.compile('3.',re.S)
print(re.findall(com,s)) # ['3\n']
print(re.findall('3.',s,re.S)) # ['3\n']
# re.findall()
s = '123abc123\ndef456'
print(re.findall('\d+',s)) # ['123', '123', '456']
# re.match():从开头搜索,搜索到了就有,没搜索到就是none
res = re.match('\d+',s)
print(res) # <re.Match object; span=(0, 3), match='123'>
print(res.group()) # 123
# re.search():搜索第一个匹配结果,找到了就不找了
res = re.search('\d+',s)
print(res) # <re.Match object; span=(0, 3), match='123'>
print(res.group()) # 123
# re.split():按照匹配规则切割
s1 = 'abc324asdfk234lkjsf324'
print(re.split('\d+',s1)) # ['abc', 'asdfk', 'lkjsf', '']
# re.sub(): 按照匹配规则替换(**********)
print(re.sub('\d+','***',s1)) # abc***asdfk***lkjsf***
print(re.sub('\d+','%%%%%',s1)) # abc%%%%%asdfk%%%%%lkjsf%%%%%
# re.subn(): 按照匹配规则替换,并计数
print(re.subn('\d+','***',s1)) # ('abc***asdfk***lkjsf***', 3)
# 分组: 一个括号里的叫一个分组, django, 了解
s = 'abc123edf456'
res = re.search('abc(?P<abc>\d+)edf(?P<edf>\d+)',s)
print(res.groupdict()) # {'abc': '123', 'edf': '456'}
3. 爬虫
import re
import requests
res = requests.get('http://duanziwang.com/')
data = res.text
res = re.findall(' <div class="post-content"> <p>(.*?)</p> </div>',data)
for i in res:
print(i)
import re
import os
import requests
'http://www.xiaohuar.com/list-2-8.html'
for i in range(1,9):
url = f'http://www.xiaohuar.com/list-2-{i}.html'
res = requests.get(url)
data = res.text
res = re.findall('src="(.*?.jpg)"',data)
for i in res: # type:str
if i.startswith('/d/file'):
i = f'http://www.xiaohuar.com{i}'
img_name = i.split('/')[-1]
img_path = os.path.join('img',img_name)
res = requests.get(i)
img_content = res.content # 针对图片/视频/音频需要用content
with open(img_path,'wb') as fw:
fw.write(img_content)
fw.flush()
print(f'下载图片{img_name}')
4. collections模块
# collections模块:复杂的数据类型
# 有名元组
# namedtuple是一个函数,它用来创建一个自定义的tuple对象,并且规定了tuple元素的个数,并可以用属性而不是索引来引用tuple的某个元素。这样一来,我们用namedtuple可以很方便地定义一种数据类型,它具备tuple的不变性,又可以根据属性来引用,使用十分方便。
from collections import namedtuple
point = namedtuple('point',['x','y'])
p = point(1,2)
print(p.x) # 1
print(p.y) # 2
# 默认字典
# 使用dict时,如果引用的Key不存在,就会抛出KeyError。如果希望key不存在时,返回一个默认值,就可以用defaultdict。
#注意默认值是调用函数返回的,而函数在创建defaultdict对象时传入。除了在Key不存在时返回默认值,defaultdict的其他行为跟dict是完全一样的。
from collections import defaultdict
# dic = {'a':1}
# print(dic['b']) # 报错
dic = defaultdict(lambda :'nan') # dic = {} # 如果找不到赋了一个默认值
dic['a'] = 1
print(dic['a']) # 1
print(dic['c']) # nan
# 双端队列
# 使用list存储数据时,按索引访问元素很快,但是插入和删除元素就很慢了,因为list是线性存储,数据量大的时候,插入和删除效率很低。deque是为了高效实现插入和删除操作的双向列表,适合用于队列和栈。deque除了实现list的append()和pop()外,还支持appendleft()和popleft(),这样就可以非常高效地往头部添加或删除元素。
lis = [1,2,3] # 线性表
lis.append(4)
print(lis) # [1,2,3,4]
from collections import deque # 链表
de = deque([1,2,3])
de.append(4)
print(de) # deque([1, 2, 3, 4])
de.appendleft(0)
print(de) # deque([0,1, 2, 3, 4])
de.popleft()
de.popleft()
print(de) # deque([2, 3, 4])
# 计数器
from collections import Counter
s = 'programming'
dic = {}
for i in s:
if i in dic:
dic[i] += 1
else:
dic[i] = 1
print(dic) # {'p': 1, 'r': 2, 'o': 1, 'g': 2, 'a': 1, 'm': 2, 'i': 1, 'n': 1}
c = Counter() # 字典
for i in s:
c[i] += 1
print(c) # Counter({'r': 2, 'g': 2, 'm': 2, 'p': 1, 'o': 1, 'a': 1, 'i': 1, 'n': 1})