python进阶之路
Day12
hello world!今日是python学习的第十二天,我将会在下面文章对基础语法进行一些介绍,主要为生成器的学习、模块与包的学习、函数式编程的标准写法、hashlib的加密操作的学习、正则语法的初步学习等。
1 生成器
生成器的本质为迭代器
生成器本身其实是能产生多个数据的容器,而不是真正保存数据的容器。
1.1怎么创建生成器
调用带有yield关键字的函数就能得到一个生成器。
调用普通函数会执行函数体,获取函数返回值
def func1():
print('abc')
return 100
result = func1()
print(result)
调用带有yield关键字的函数:a.不执行函数体 b.获取到的是生成器对象
def func2():
#yield
print('abc')
return 100
yield
result = func2()
print(result) # <generator object func2 at 0x000001A1A63B82C8>
1.2 生成器怎么生产数据
a.一个生成器生产多少数据? - 就看执行生成器对应的函数体,在函数结束的时候会遇到几次yield,遇到几次生产多少。
b.生成器生产的数据是哪些? - 看每次遇到yield,yield后面的数据是什么,生成的数据就是什么。
print(next(result))
print(list(result))
def func3():
yield
print('=======')
yield
print('++++++')
gen1 = func3()
print(gen1)
print(len(list(gen1)))
def func4(n):
yield
if n % 2:
yield
print('end')
gen2 = func4(4)
print(len(list(gen2)))
gen3 = func4(5)
print(len(list(gen3)))
c.生成器生产的数据是哪些?
def func5():
yield 10
yield 100
gen4 = func5()
print(list(gen4))
1.3 生成器产生数据的原理
调用函数创建生成器对象的时候不会执行函数体,当获取生成器中的元素的时候才会执行函数体。
第一次获取第一个元素的时候从函数开始执行,执行遇到第一个yield就会停下来,并且将yield后面的数据作为这次获取到的元素。下次获取元素的时候会从上一次结束的位置接着往后执行函数体,直到遇到下一个yield停下来,并且将yield后面的数据作为新的元素,以此类推。
如果从上次函数开始到函数结束都没有遇到yield,那么这个生成器就不会在创建数据,如果进行next取元素,就会报错。
def func6():
print('第一个:')
yield 10
print('第二个:')
yield 100
print('第三个:')
yield 1000
gen5 = func6()
next(gen5)
next(gen5)
def func7(n):
for x in range(n):
yield x * 2
gen6 = func7(10)
print(next(gen6))
print(next(gen6))
练习:写一个学号的生成器,能够产生stu0001到stu9999的学号
def stunum():
for x in range(1,10000):
yield f'stu{x:0>4}' f'stu{str(x).zfill(4)}'
stunums = stunum()
print(next(stunums))
print(next(stunums))
注意:每次调用函数的时候,都是在创造一个新的生成器对象。
print(next(stunum())) # 创造了一个新的生成器,只会取到第一个
def stunum(str1,n):
for x in range(1,10**n):
yield str1+str(x).zfill(n)
stunums1 = stunum('python',4)
print(next(stunums1))
2 模块
2.1 什么是模块
一个py文件就是一个模块
2.2 模块之间的数据交流
我们可以在任意一个模块中使用另外一个模块的中所有的全局变量(普通变量\函数\类)
如果想要在一个模块中使用另外一个模块的内容,必须先导入模块。
import random
2.3 模块的分类
1)系统的模块 - 系统已经定义好的模块,程序员可以直接导入使用。
2)第三方库模块(其他程序员或者机构定义的模块) - 需要先下载导入到工程中以后在导入使用。
3)自定义模块(在工程中创建的模块) - 程序员直接导入使用
2.4 导入模块
1) 导入方式
import 模块名 - 导入指定模块,导入后可以使用这个模块中所有的全局变量。使用方式:模块名.变量
from 模块名 import 变量1,变量2,变量3,。。。 - 导入指定模块,导入后可以使用这个模块中指定的变量。直接用。
from 模块名 import * - 导入指定模块,导入后可以使用模块中所有的变量。
2)重命名
import 模块名 as 新模块名 - 对模块进行重命名(与代码冲突或使用方便),重命名后通过新模块名使用模块。
from 模块名 import 变量1 as 新变量1,。。。 - 导入模块的时候对指定的变量进行重命名。
# 1.import 模块名
import test
print(test.a)
print(test.x)
test.func1()
import random
print(random.randint(1,10))
# 2.from 模块名 import 变量
from test import x,func1
from random import randint
print(randint(1,9))
print(x)
# 3. from - import *
from test import *
print(a)
print(x)
func1()
# 对模块进行重命名
import test as TS
test = 10
print(test)
print(TS.a)
print(TS.x)
from test import a as t_a
a = 300
print(a, t_a)
import time
import random
import math
3) 导入模块的原理
当代码执行到import 或者from - import 导入模块的时候,系统会自动进入指定模块,执行这个模块中所有的代码。
如果一个模块中的部分代码不希望在被导入的时候执行,就将这段代码写入写在 if name == main: 中即可(每个模块都有一个__name__属性,这个属性保存的是模块名,默认值都是文件名。当我们直接执行某个模块的时候,这个模块的__name__的的值会自动变成__main__,其他没有被执行的__name__的值都是自己的文件名)
import test
from test import name
import test1
if __name__ == '__main__':
# 将在被导入的时候不希望被执行的代码放到这个if语句里面即可。
def func1():
print('注册')
def func2():
print('登录')
def func3():
print('退出')
def main():
# 实现当前模块的功能(功能的实现全靠函数和类)
func1()
func2()
func3()
pass
if __name__ == '__main__':
main()
3 包
3.1 什么是包
包就是包含__init__.py文件的文件夹
3.2 怎么使用包中的模块的里面的内容
1) import 包.模块
2) from 包 import 模块
3) from 包.模块 import 变量1,变量2,。。。
# import file.fileManager
# file.fileManager.read_file()
# import file.fileManager as FM
# FM.read_file()
# from file import fileManager
# fileManager.read_file()
# from file.fileManager import f_name,read_file
# print(f_name)
# read_file()
3.3 导入包的原理
导入包的时候,会先执行包的__init__.py文件中的所有的代码
from file import read_file
read_file()
3.4 重复导入
import在导入模块或者包的时候会自动检查对应模块或者包之前是否已经重复导入了,如果已经导入不会再重复导入。
# include aa.h(include不会自动检测是否已经导入,需要考虑此类问题)
import test1
import test1
4 常用的标准库
4.1 标准库和第三方库
标准库 - python自己提供的模块或者包,用的时候可以直接导入
第三方库 - 由别人提供的模块或者包,需要先安装或者下载后才可以导入。
4.2 常用的标准库
os模块 - 提供文件或者文件夹操作的相关功能(例如:创建文件或者文件夹,删除文件或者文件夹。。。)
sys模块 - 提供系统相关的操作
time模块 - 时间相关操作
datetime模块 - 时间相关的操作
json模块 - json操作
re模块 - 正则表达式相关操作
hashlib - 加密模块
turtle模块 - 画图
1) time() - 获取当前时间,返回的是时间戳
2) sleep(时间) - 让程序睡眠指定时间(秒)
3) localtime() - 获取当前的本地时间
4) 将时间戳对应的时间转换成struct_time(转化成我们认识的时间值)
import time
t1 = time.time()
time.sleep(1)
t2 = time.time()
print(t2 - t1)
print(t1,type(t1))
补充:时间戳(加密方便)
时间戳就是当前时间到格林威治时间1970年1月1日0时0分0秒的时间差,单位为秒
t1 = 1596615882.7843628 # 四个字节保存时间
#’2020/8/5/16:31:50‘ 17个字节保存时间。
print(t1/3600/24/30/12)
print(time.localtime(t1))
from datetime import datetime
print(datetime.now())
5 hashlib模块的学习(加密算法)
5.1 hashlib模块的使用
import hashlib
hashlib是python3.x中提供的一个标准库,专门用来对数据进行hash加密的,常用的加密算法是:md5、shaxxx。
hash算法又叫摘要算法或者叫做离散算法
5.2 hash加密的特点
a.同样的内容使用相同的算法加密之后的结果是一样的
b.加密之后的结果不可逆
c.不管原数据的大小或者长度是多少,使用同一种加密算法得到的密文(摘要)的长度是一样的。
5.3 生成摘要(对数据进行加密)
1) 根据算法创建hash对象
# hashlib.算法名()
hash = hashlib.md5()#(sha1.....)
2) 使用hash对象对指定的数据加密
hash对象.update(数据) - 对指定的数据加密(这儿的数据必须是二进制数据,类型是bytes)
补充:二进制和字符串之间的相互转换
a. 字符串->二进制
bytes(字符串,encoding = ’utf-8‘))
字符串.encode()
b. 二进制->字符串
str(二进制,encoding = ‘utf-8’)
二进制.decode(encoding=‘utf-8’)
pw = '123456'
hash.update(bytes(pw,encoding='utf-8'))
3) 获取摘要(获取加密后的密文)
di = hash.hexdigest()
print(di)
4) hash加密的应用2:生成数据摘要,确保原数据的完整性
#with open('test.txt','rb') as f:
content = f.read()
#hash2 = hashlib.md5()
#hash2.update(content)
#print(hash2.hexdigest())
6 正则表达式
from re import fullmatch
fullmatch(正则表达式,字符串) - 判断正则表达式与字符串是否完全匹配,如果不能匹配返回None。
##### 6.1 什么是正则表达式?
正则表达式是处理字符串的工具
6.2 正则的语法(通用)
1.匹配符号====
1)普通字符
除了在正则中有特殊功能和特殊意义的字符以外的字符。
普通字符在正则表达式中表示这个字符本身
re_str = r'abc'
print(fullmatch(re_str,'abc'))
2) . - 匹配一个任意字符
re_str = r’.bc’ 匹配一个长度是3的字符串,后两个字符是bc,第一个字符是任意字符。
print(fullmatch(re_str,'abc'))
print(fullmatch(re_str,'asbc'))
3) \w - 匹配任意一个数字、字母、下划线(在ASCII表中)
re_str = r'\w123'
print(fullmatch(re_str,'_123'))
print(fullmatch(re_str,'胡123')) # \w不在ASCII表中的不受控制,可以匹配任意不在ASCII表中的字符。
4) \d - 匹配任意一个数字字符
re_str = r'\d\dabc'
print(fullmatch(re_str,'45abc'))
print(fullmatch(re_str,'f5abc'))
5) \s - 匹配任意一个空白字符
常见的空白字符:’ ‘、’\n‘、’\t‘
re_str = r'\d\d\s\d'
print(fullmatch(re_str,'12\t5'))
print(fullmatch(re_str,'12\n5'))
print(fullmatch(re_str,'12 5'))
print(fullmatch(re_str,'12 5'))# None
6) \大写字母(\W,\S,\D)
\大写字母的功能和\小写字母的功能是相反的
\S - 匹配任意一个非空白字符
\D - 匹配任意一个非数字字符
7)[字符集] - 匹配字符集中的任意一个字符
注意:a.一个[]只能匹配一个字符
b.[字符1-字符2]中两个字符之间的-表示范围:字母1到字母2,并且要求字符1的编码值必须小于字符2.
[abc] - 匹配a或者b或者c
[a-z] - 匹配任意一个小写字母
[A-Z] - 匹配任意一个大写字母
[a-zA-Z] - 匹配任意一个字母
[0-9] - 匹配任意一个数字
[\u4e00-\u9fa5] - 匹配任意一个中文字符
re_str = r'[xam]123'
print(fullmatch(re_str,'a123'))
print(fullmatch(re_str,'q123'))
re_str = r'[a-z]bc'
print(fullmatch(re_str,'sbc'))
re_str = r'[2-9]asd'
print(fullmatch(re_str,'4asd'))
re_str = r'[0-9a-zA-Z_]asd' abc前面是任意数字、字母或者下划线
print(fullmatch(re_str,'_asd'))
re_str = r'[\dxy]asd'
print(fullmatch(re_str,'yasd'))
8) [^字符集] - 匹配任意一个不在字符集中的字符
[^abc] - 匹配一个非a、b、c的任意一个字符
re_str = r'[^xy]abc'
print(fullmatch(re_str,'sabc'))
注意:
a.[]中的只有放在最前面的时候才有特殊意义,在其他位置的时候表示字符本身。
b. []中的减号只有在两个字符之间的时候才有意义,否则也是表示字符本身。
re_str = r'[x^y]abc'
print(fullmatch(re_str,'^abc'))
re_str = r'[09-]abc'
print(fullmatch(re_str,'9abc'))
=2.匹配次数
1) * - 匹配0次或多次
a* - a匹配0次或者多次
\d* - 任意数字出现0次或者多次
[abc]* - [abc]匹配0次或者多次
re_str = r'a*123'
print(fullmatch(re_str,'aaa123'))
re_str = r'\d*123'
print(fullmatch(re_str,'123'))
print(fullmatch(re_str,'4566123'))
2) + - 匹配一次或者多次
re_str = r'\d+abc'
print(fullmatch(re_str,'234abc'))
print(fullmatch(re_str,'abc'))
3)? - 匹配一次或者0次
re_str = r'm?123'
print(fullmatch(re_str,'123'))
print(fullmatch(re_str,'m123'))
print(fullmatch(re_str,'mm123'))
4) {}
{N} - 匹配N次
{M,N} - 匹配M到N次
{M,} - 匹配至少M次
{,N} - 匹配最多N次
print(fullmatch(r'\d{3}abc','123abc'))
print(fullmatch(r'x{3,5}abc','xxxxabc'))
作业1:写一个正则能够匹配任意一个整数
作业2:写一个正则能够匹配任意1个QQ号(3到12位并且第一位数字不能是0)
re_str = r'[1-9+-]\d*'
re_str1 = r'[^0]\d{3,12}'
print(fullmatch(re_str,'45244545'))
print(fullmatch(re_str1,'55446546865'))