17_Python的常用模块

1.随机数模块 random

    1.随机小数

import random

# (0,1)随机取浮点数
random.random()  # 0.17988578778011

# (1, 3)取指定范围的浮点数
random.uniform(1,3)  # 2.3793286185319555

    2.随机整数

import random

# [1, 3]随机取整数
random.randint(1, 3)  # 1

# [1, 3)随机取整数
random.randrange(1, 3)  # 1

    3.随机选择返回一个和随机选择返回多个

import random

# [可迭代序列]取随机值
random.choice([11, 22, 33])  # 22

# [可迭代序列]取随机2个值,返回的个数为函数的第二个参数
random.sample([11, 22, 33], 2)  # [11, 22]

    4.打乱列表序列

import random

# 随机打乱列表的序列
item = [1, 2, 3, 4, 5]
random.shuffle(item)
print(item)  # [2, 1, 4, 5, 3]

    5.其他方法

import random

# 以长整型的形式返回用nbit位来表示的随机数
random.getrandbits(nbit)
# 生成一个16比特长的随机整数
random.getrandbits(16)  # 20962

# 用给定的数a设置随机种子,不给参数a则用当前时间设置随机种子
random.seed(a=None)

# 随机数产生与种子有关,如果种子是1,第一个数必定是这个
random.seed(1)  # 产生种子1对应的序列
print(random.random())  # 0.13436424411240122
print(random.random())  # 0.8474337369372327

random.seed(1)  # 产生种子1对应的序列
print(random.random())  # 0.13436424411240122
print(random.random())  # 0.8474337369372327

    6.生成指定长度的随机验证码

import random


def v_code(num):
    code = ""
    for i in range(num):
        num = random.randint(0, 9)
        # alf = chr(random.randint(65, 90))
        alf = chr(random.choice([random.randint(65, 90),random.randint(97, 122)]))
        add = random.choice([num, alf])
        code = "".join([code, str(add)])
    return code


print(v_code(6))

2.与系统相关模块 os

    1.os模块概述
        os模块是与操作系统交互的一个接口
        导入语法: import os

    2.文件操作

import os

# remove 删除一个文件
os.remove("test1/111")  # 删除指定路径的文件,如果指定的路径是一个目录,将抛出异常FileNotFoundError
os.unlink("a.txt")  # 删除文件,如果文件是一个目录,将抛出异常FileNotFoundError

# 递归删除目录和文件夹
for root, dirs, files in os.walk(top, topdown=False):
    for name in files:
        os.remove(os.path.join(root, name))
    for name in dirs:
        os.rmdir(os.path.join(root, name))

# 递归遍历目录和文件个数
    # dir_count: 不仅会统计一级子文件夹还会统计二级三级子文件夹依次类推一级子文件夹若有一个子文件夹会记作两个
    dir_count = 0
    # file_count: 不仅会统计文件夹下的文件,还会统计子文件夹下的文件
    file_count = 0
    for root, dirs, filenames in os.walk(file_path):
        for dir in dirs:
            dir_count += 1
        for file in filenames:
            file_count += 1
    print("dir_count", dir_count)
    print("file_count", file_count)

# rename 重命名文件/目录
os.rename("test1", "test1")

    3.目录操作

import os

# getcwd获取当前工作目录,即当前python脚本工作目录路径
print(os.getcwd())  # G:\PycharmProjects\11_模块\lnh_massage

# chdir改变当前脚本的工作目录,相当于shell下的cd命令
os.chdir("test1")
print(os.getcwd())  # G:\PycharmProjects\11_模块\lnh_massage\test1
os.chdir("..")
print(os.getcwd())  # G:\PycharmProjects\11_模块\lnh_massage

# curdir返回当前目录
print(os.curdir)  # .

# pardir获取当前父目录字符串名
print(os.pardir)  # ..

# makedirs 可递归创建文件夹
os.makedirs("makir1/mkdir2")

# removedirs 文件夹为空则可递归删除文件夹,知道非空为止
os.removedirs("makir1/mkdir2")

# mkdir 生成单级目录
os.mkdir("test2")

# rmdir 删除单级空目录,目录不为空则无法删除
os.rmdir("test2")

# listdir 列出指定文件下的所有文件和子目录,包含影藏文件,返回一个列表
print(os.listdir("test1"))

# stat 获取文件/目录信息
print(os.stat(r"G:\PycharmProjects\11_模块\lnh_massage"))
"""stat结构
    st_mode: inode 保护模式
    st_ino: inode 节点号
    st_dev: inode 驻留的设备
    st_nlink: inode 的链接数
    st_uid: 所有者的用户ID
    st_gid: 所有者的组ID
    st_size: 普通文件以字节为单位的大小,包含等待某些特殊文件的数据
    st_atime: 上次访问的时间
    st_mtime: 最后一次修改的时间
    st_ctime: 由操作系统报告的"ctime",在某些系统上(如Unix)是最新的元数据更改的时间在其它系统上(如Windows)是创建时间
"""

    4.系统相关操作

import os

# sep 查看操作系统的特定路径分割符
print(os.sep)  # Windows为: "\",Linux为: "/"

# linesep 查看当前平台使用的终止符
print("终止符", os.linesep)  # win下"\r\n",linux下"\n"

# pathsep 查看用于分割文件路径的字符串
print("分隔文件", os.pathsep)  # win下",",linux下":"

# name 以字符串指示查看当前使用平台
print("使用平台", os.name)  # win下"nt",linux下"posix"

# system 用于运行shell命令
os.system("ping 127.0.0.1")

# popen 运行系统命令并返回执行结果,win平台: dir Linux平台: ls, pwd等
r = os.popen("pwd") 
print(r.read())  # /Users/tangxuecheng

# urandom 返回一个指定长度的bytes类型数据
b = os.urandom(5)
print(b)  # b'\xbc\xd9\xbc\xb0\xb8'

    5.path相关操作

import os

# environ 获取系统环境变量
print(os.environ)

# path.abspath() 返回规范化的path绝对路径
print(os.path.abspath(r"G:\PycharmProjects\11_模块\lnh_massage\test1"))
# G:\PycharmProjects\11_模块\lnh_massage\test1

# path.split 将path分割成目录和文件名,返回元组
print(os.path.split(r"G:\PycharmProjects\11_模块\lnh_massage\test1"))
# ('G:\\PycharmProjects\\11_模块\\lnh_massage', 'test1')

# path.dirname 返回path.split的第一个元素,目录
print(os.path.dirname(r"G:\PycharmProjects\11_模块\lnh_massage\test1"))
# G:\PycharmProjects\11_模块\lnh_massage

# basename 返回path.split的第二个元素,文件名
print(os.path.basename(r"G:\PycharmProjects\11_模块\lnh_massage\test1"))  # test1

# path.exists 判断path是否存在,返回布尔值
print(os.path.exists(r"G:\PycharmProjects\11_模块\lnh_massage\test1"))  # True

# path.isabs 判断path是否是绝对路径,返回布尔值
print(os.path.isabs(r"G:\PycharmProjects\11_模块\lnh_massage\test1"))  # True

# path.isfile 判断path是否是一个存在的文件,返回布尔值
print(os.path.isfile(r"G:\PycharmProjects\11_模块\lnh_massage\test1"))  # False

# path.isdir 判断path是否是一个存在的目录
print(os.path.isdir(r"G:\PycharmProjects\11_模块\lnh_massage\test1"))  # True

# path.join 路径拼接,会自动去找当前操作系统的路径分割符拼接
a = r"G:\PycharmProjects"
b = r"11_模块\lnh_massage\test1"
print(os.path.join(a, b))  # G:\PycharmProjects\11_模块\lnh_massage\test1

# path.getatime 返回path所指向的文件或目录最后一次存取时间
print(os.path.getatime(r"G:\PycharmProjects\11_模块\lnh_massage\test1"))
# 1553962262.1905563

# path.getmtime 返回path所指向的文件或目录最后一次修改时间
print(os.path.getmtime(r"G:\PycharmProjects\11_模块\lnh_massage\test1"))
# 1553962262.1905563

# path.getsize 返回path所指向的文件的大小,单位为字节
print(os.path.getsize(r"G:\PycharmProjects\11_模块\lnh_massage\test1"))  # 397

    6.进程相关

import os

# 创建一个新的进程,返回的pid为新的进程的PID
pid = os.fork()

# 获取当前进程的PID号
print(os.getpid())  # 10181

# 获取当前进程父进程的PID号
print(os.getppid())  # 10148

# 结束进程,参数是一个整数表示进程的结束状态
print(os._exit(1))

# 等待子进程退出进行处理
p, status = os.wait()  # 返回值: 一个二元元组,第一个值为退出的子进程PID,第二个值为子进程退出状态
os.WEXITSTATUS(status)  # 获取结束状态原数

3.与解释器相关模块 sys

    1.sys模块概述
        sys模块是与python解释器交互的一个接口
        导入语法: import sys

    2.变量

import sys

# 模块搜索路径 path[0] 是当前脚本程序的路径名,否则为 ''
sys.path
"""执行结果
    ['D:\\Program Files (x86)\\Scripts\\ipython.exe',
     'd:\\program files (x86)\\python37.zip',
     'd:\\program files (x86)\\DLLs',
     'd:\\program files (x86)\\lib',
     'd:\\program files (x86)',
     '',
     'd:\\program files (x86)\\lib\\site-packages',
     'd:\\program files (x86)\\lib\\site-packages\\IPython\\extensions',
     'C:\\Users\\Administrator\\.ipython']
"""

# 已加载模块的字典
sys.modules

# 版本信息字符串
sys.version  # '3.7.7 (default, Mar 10 2020, 15:43:33) \n[Clang 11.0.0 (clang-1100.0.33.17)]'


# 版本信息的命名元组
sys.version_info  # sys.version_info(major=3, minor=7, micro=7, releaselevel='final', serial=0)


# 操作系统平台名称信息
sys.platform  # 'darwin'

# 命令行参数 argv[0] 代表当前脚本程序路径名
sys.argv  # ['/usr/local/bin/ipython']

# 获得Python版权相关的信息
sys.copyright

# 获得Python内建模块的名称(字符串元组)
sys.builtin_module_names

    3.标准输入输出

import sys

# 标准输入文件对象,多用于input()
sys.stdin
s = sys.stdin.read(10)  # 默认从键盘获取
print(s)

# 标准输出文件对象,多用于print()
sys.stdout
s = sys.stdout.write("hello world!\n")  # hello world!
print(s)  # 13

# 标准错误输出文件对象,用于输出错误信息
sys.stderr
s =  sys.stderr.write("错误信息输出\n")  # 错误信息输出
print(s)  # 7

# 查看 标准输入/输出/错误输出 的文件描述符
print(sys.stdin.fileno())  # 0
print(sys.stdout.fileno())  # 1
print(sys.stderr.fileno())  # 2

    4.方法

import sys

# 结束一个进程并抛出异常,传入一个正整数表示结束状态
sys.exit()  # 不写参数默认为0正常结束

# 传入字符串表示打印进程结束语 sys.exit("end")
sys.exit("end")

# 得到递归嵌套层次限制(栈的深度)
sys.getrecursionlimit()  # 3000

# 得到和修改递归嵌套层次限制(栈的深度)
sys.setrecursionlimit(n)

# 指定字符串加入小数据池
a = sys.intern('hello!@'*20)
b = sys.intern('hello!@'*20)
print(a is b)  # True

# 获取文件名: 获取当前位置所在的文件名
print(sys._getframe().f_code.co_filename)  # <ipython-input-10-dfaee55b6107>

# 获取函数名: 获取当前位置所在的函数名
print(sys._getframe().f_code.co_name)  # <module>

# 获取行号: 当前位置所在的行号
print(sys._getframe().f_lineno)  # 1

    5.进度条示例

import sys
import time

for i in range(100):
    sys.stdout.write("#")  # 向屏幕显示相应的内容
    time.sleep(0.1)
    sys.stdout.flush()  # 刷新缓存

    6.异常处理和status

import sys

try:
    sys.exit(1)
except SystemExit as e:
    print(e)

4.正则模块 re

    1.正则表达式概述

        1.正则表达式就是匹配字符串内容的一种规则

        2.模块导入语法: import re

        3.元字符

            . 匹配除换行符以外的任意字符
            \w 匹配字母或数字或下划线
            \s 匹配任意的空白符
            \d 匹配数字
            \n 匹配一个换行符
            \t 匹配一个制表符
            \b 匹配一个单词的结尾
            ^ 匹配字符串的开始
            $ 匹配字符串的结尾
            \W 匹配非字母或数字或下划线
            \D 匹配非数字
            \S 匹配非空白符
            a|b 匹配字符a或字符b
            () 匹配括号内的表达式,也表示一个组
            [...] 匹配字符组中的字符
            [^...] 匹配除了字符组中字符的所有字符

        4.量词

            * 重复零次或更多次
            + 重复一次或更多次
            ? 重复零次或一次
            {n} 重复n次
            {n,} 重复n次或更多次
            {n,m} 重复n到m次

        5.贪婪和非贪婪

            .* 默认为贪婪匹配模式,会匹配尽量长的字符串
            .*? 加上?为将贪婪匹配模式转为非贪婪匹配模式,会匹配尽量短的字符串
            常用示例:
                *? 重复任意次,但尽可能少重复
                +? 重复1次或更多次,但尽可能少重复
                ?? 重复0次或1次,但尽可能少重复
                {n,m}? 重复n到m次,但尽可能少重复
                {n,}? 重复n次以上,但尽可能少重复

        6.分组

            () 可以为正则表达式建立一个子组,子组可以看做内部的整体
            子组的概述:
                1.子组可以改变重复元字符的重复行为,增加子组后对正则表达式整体的匹配内容没有影响
                2.子组在某些操作中可以对子组匹配内容单独提取,子组通常不要交叉使用
                3.每个正则表达式可以有多个子组,由外到内由左到右依次为第一子组,第二子组
            捕获组和非捕获组(命名组和非命名组)
                1.子组命名格式: (?Pabc)
                2.很多编程接口可以直接通过名字获取子组的匹配内容
                3.捕获组中的正则表达式可以通过名字重复调用: (?P=name)

In [43]: import re

In [44]: re.search("(ab)+", "ababababab").group()
Out[44]: 'ababababab'

In [45]: re.search("(?P<dog>ab)cdef(?P=dog)", "abcdefabcde").group()
Out[45]: 'abcdefab'

    2.普通字符

import re

# 匹配相应的普通字符
print(re.findall("coco", "my name is coco hao are you"))  # ['coco']

    3.元字符: . ^ $ [] | () \

import re

# .匹配除了\n以外的所有字符,一个点代指1个字符
print(re.findall("m.....e", "my name is coco hao are you"))  # ['my name']

# .匹配包括\n的所有字符,需要传入第三个参数re.S
print(re.findall(".*", "hello\nworld!"))  # ['hello', '', 'world!', '']
print(re.findall(".*", "hello\nworld!", re.S))  # ['hello\nworld!', '']
print(re.search(".*", "hello\nworld!").group())  # hello
print(re.search(".*", "hello\nworld!", re.S).group())
"""
    hello
    world!
"""

# ^只能在字符串开头匹配内容,表示匹配一个字符串的开始位置
print(re.findall("^m..n", "my name is coco hao are you"))  # ['my n']

# $只能在字符串结尾匹配内容,表示匹配一个字符串的结尾位置
print(re.findall("e...u$", "my name is coco hao are you"))  # ['e you']

# []字符集,匹配括号范围内的任意一个字符,字符集里的功能符号只有- ^ \
print(re.findall("x[yz]", "xyaaaxz"))  # ['xy', 'xz']
# -范围
print(re.findall("x[a-z]", "xyappxcappxzapp"))  # ['xy', 'xc', 'xz']
# ^非
print(re.findall("x[^a-z]", "xyappxcappxzappx1"))  # ['x1']

# |管道符-->或,匹配两边任意一个正则表达式符合条件的情况
print(re.findall("ac|b", "123ac566546b"))  # ['ac', 'b']
print(re.search(r"^[a-z]{2,8}@(139|163)\.com$", "xc@139.com").group(1))  # 139
print(re.match(r"[a-z]{2,8}@(139|163)\.com$", "xuechang@163.com").group(1))  # 163

# ()分组,使用括号可以为正则表达式建立一个子组,子组可以看做内部的整体
print(re.findall("(abc)+", "abc11abc22abc33"))  # ['abc', 'abc', 'abc']
# search 如果search中有分组的话,通过group(n)就能够拿到group中的匹配的内容
# \1表示和第一个分组中的值相同
print(re.search(r"<(\w*)>(.*)</\1>", "<h1>xc@139.com</h1>").group(2))  # xc@139.com

# (?P<name>正则表达式) 表示给分组起别名,(?P=name) 表示引用别名为分组匹配到的字符串
ret = re.search("(?P<name>[a-z]+)(?P<age>\d+)","coco26echo30").group("name")
print(ret)  # coco
ret = re.search(r"<(?P<h>\w*)>(.*)</(?P=h)>", "<h1>xc@139.com</h1>").group("h")
print(ret)  # h1

# ?:取消分组优先显示
ret= re.findall("www\.(baidu|163)\.com", "aawww.baidu.combb")
print(ret)  # ['baidu']
ret= re.findall("www\.(?:baidu|163)\.com", "aawww.baidu.combb")
print(ret)  # ['www.baidu.com']

# \转义元字符
print(re.findall("5\*3\+2", "5*3+2-10"))  # ['5*3+2']
# \d: 匹配任意十进制数,相当于[0-9]
print(re.findall("\d+", "1+(2*3+5-(2-(5-4)))"))  # ['1', '2', '3', '5', '2', '5', '4']
# \D: 匹配任意非十进制数,相当于[^0-9]
print(re.findall("\D+", "1+(2*3+5-(2-(5-4)))"))  # ['+(', '*', '+', '-(', '-(', '-', ')))']
# \s: 匹配任何空白字符,相当于[\n\t\r\f\v]
print(re.findall("\s+", "hello world"))  # [' ']
# \S: 匹配任何非空白字符,相当于[^\n\t\r\f\v]
print(re.findall("\S+", "hello world"))  # ['hello', 'world']
# \w: 匹配任何字母数字,相当于[a-zA-z0-9_]
print(re.findall("\w+", "hello world 12345"))  # ['hello', 'world', '12345']
# \W: 匹配任何非字母数字,相当于[^a-zA-z0-9_]
print(re.findall("\W+", "hello world 12345"))  # [' ', ' ']
# \b: 匹配一个特殊字符边界,如空格 & # 等,r原生字符串:r后面的字符串pythonIDE不解释,交给re解释
print(re.findall(r"lo\b", "hello hello#hello&"))  # ['lo', 'lo', 'lo']
# \B: 匹配一个特殊字符非边界,如非空格 非& 非# 等,r原生字符串:r后面的字符串pythonIDE不解释,交给re解释
print(re.findall(r"el\B", "hello hello#hello&"))  # ['el', 'el', 'el']
# \A: 匹配开始位置,相当于^
print(re.findall("\A\w+", "hello world 12345"))  # ['hello']
# \Z: 匹配结束位置,相当于$
print(re.findall("\d+\Z", "hello world 12345"))  # ['12345']
# \A...\Z: 绝对匹配,以什么开始以什么结束,相当于 ^...$
print(re.findall("\A/\w+/\w+\Z", "/Users/tangxuecheng"))  # ['/Users/tangxuecheng']

    4.量词: * + ? {}

# *匹配0-无穷次前面的内容
print(re.findall("^d*", "dddddefghddd"))  # ['ddddd']

# +匹配1-无穷次的内容
print(re.findall("d+", "dddddefghddd"))  # ['ddddd', 'ddd']

# ?匹配0次或者1次的内容
print(re.findall("ghf?", "dddddefghddd"))  # ['gh']

# {n}匹配指定重重复n次的内容
print(re.findall("ghd{3}", "dddddefghddd"))  # ['ghddd']
# {m,n}匹配指定重复m次到n次的内容
print(re.findall("ghd{0,2}", "dddddefghddd"))  # ['ghdd']

    5.查找方法: findall, search, match, fullmatch

# findall(pattern, string, flags=0)查找方法: 返回一个列表值为所有匹配上的项
# findall会优先显示分组中的内容,要想取消分组优先(?:正则表达式)
ret = re.findall('\d+', '19874ashfk01248')
print(ret)  # ['19874', '01248']
ret1 = re.findall('\s+', '19874ashfk01248')
print(ret1)  # []

# search(pattern, string, flags)查找方法: 匹配一个字符串,匹配到返回math对象,没有匹配到返回None
ret = re.search('\d+', '@$19874ashfk01248')
print(ret)  # <re.Match object; span=(2, 7), match='19874'>
# 返回的对象通过group来获取匹配到的第一个结果
if ret:
    print(ret.group())  # 19874
ret = re.search('\s+', '19874ashfk01248')  # 返回值类型: None 如果没有匹配上就是None
print(ret)  # None

# mach(pattern, string, flags)查找方法: 匹配一个字符串的开头位置,匹配到返回math对象,没有匹配到返回None
ret = re.match('\d+', '19874ashfk01248')  # 同search用法,不同在以字符串开始出进行匹配
print(ret)  # <re.Match object; span=(0, 5), match='19874'>
ret = re.match("a", "abc").group()
print(ret)  # a

# fullmatch(pattern, string, flags)查找方法: 要求目标字符串完全匹配
ret = re.fullmatch("\w+", "abc123")
print(ret.group())  # abc123

    6.分割和替换方法: split, sub, subn

# split(pattern, string, flags): 按照正则表达式分割字符串方法,遇到分组会保留分组内被切掉的内容
ret = re.split("[ab]", "abcd")  # 先按a分割得""和"bcd"再对""和"bcd"按b分割
print(ret)  # ['', '', 'cd']

# sub(pattern, replaceStr, string, max, flags): 替换正则表达式匹配到的内容方法,返回替换后的字符串
# 参数一正则表达式,参数二要替换的内容,参数三目标字符串,参数四最多替换几处,参数五为功能标志位
ret = re.sub("\d+", "A", "d22d33sd44", 2)
print(ret)  # dAdAsd44

# subn(pattern, repl, string, count, flags): 替换正则表达式匹配到的内容方法,返回替换后的字符串和实际替换的个数
# 参数一正则表达式,参数二要替换的内容,参数三目标字符串,参数四最多替换几处,参数五为功能标志位
ret = re.subn("\d+", "A", "d22d33sd44")
print(ret)  # ('dAdAsdA', 3)

    7.爬虫效率方法: compile
        概述: compile编译方法,节省时间:只有在多次使用某一个相同的正则表达式的时候,这个compile才会帮助我们提高程序的效率
        语法: obj = re.compile(pattern, flags) # 获取正则表达式对象,参数一是正则表达式,参数二是功能标志位,提供更丰富的匹配
        返回对象语法: res = obj.findall(string, pos, endpos) # 通过正则表达式匹配字符串,匹配到的所有结果以列表返回
        返回对象语法参数: string: 目标字符串; pos: 目标字符串的匹配开始位置; endpos: 目标字符串的匹配结束位置

import re

com = re.compile("\d+")
ret = com.findall("avc11sss22ssgg33")
print(ret)  # ['11', '22', '33']

pattern = r"(?P<name1>ab)cd(?P<name2>ab)"
# 获取正则表达式compile对象
compile_obj = re.compile(pattern, flags=0)

# ########compile对象属性########
# 标志位常量
print(compile_obj.flags)  # 32
# 正则表达式
print(compile_obj.pattern)  # (?P<name1>ab)cd(?P<name2>ab)
# 捕获组字典
print(compile_obj.groupindex)  # {'name1': 1, 'name2': 2}
# 子组个数
print(compile_obj.groups)  # 2

# compile查找方法返回一个match对象
match_obj = compile_obj.search("abcdefabcdabcdefabcde", 6, 15)

# ########match对象属性########
# 目标字符串开头位置
print(match_obj.pos)  # 6
# 目标字符串结束位置
print(match_obj.endpos)  # 15
# 正则表达式对象
print(match_obj.re)  # re.compile('(?P<name1>ab)cd(?P<name2>ab)')
# 目标字符串
print(match_obj.string)  # abcdefabcdabcdefabcde
# 分组最后一组名字
print(match_obj.lastgroup)  # name2
# 分组最后一组是第几组
print(match_obj.lastindex)  # 2

# ########match对象方法########
# 匹配到内容的开始位置
print(match_obj.start())  # 6
# 匹配到内容的结束位置
print(match_obj.end())  # 12
# 匹配到内容的起止位置
print(match_obj.span())  # (6, 12)
# 获取match对象匹配的内容,参数默认为0表示获取正则整体的匹配内容
print(match_obj.group())  # abcdab
# 参数为大于0的正整数表示获取对应子组匹配内容
print(match_obj.group(1))  # ab
# 得到所有子组匹配的内容,元祖形式返回
print(match_obj.groups())  # ('ab', 'ab')
# 得到所有捕获组匹配到的内容,字典形式返回
print(match_obj.groupdict())  # {'name1': 'ab', 'name2': 'ab'}

    8.爬虫效率方法: finditer
        概述: finditer方法处理后返回迭代器, 空间效率: 节省内存
        语法: ret = re.finditer(pattern, string, flags) # 使用正则表达式匹配目标内容返回迭代对象,迭代的每个内容为一个math对象
        参数: pattern: 正则表达式; string: 目标字符串; flags: 功能标识位

import re

ret = re.finditer("\d+", "asd22sa33")
print(ret)  # <callable_iterator object at 0x0000000003548BE0>
print(next(ret).group())  # 22
print(next(ret).group())  # 33

    9.参数flags
        概述: 辅助正则表达式,丰富匹配结果
        选项值:
            A, ASCII: 匹配ASCII字符
            S, DOTALL: 对元字符.起作用,让其可以匹配换行
            I, IGNORECASE: 匹配时忽略大小写
            L, LOCALE: 影响 “w, “W, “b, “B,做本地化识别(locale-aware)匹配
            M, MULTILINE: 可以匹配每一行的开头结尾,影响 ^ 和 $
            T, TEMPLATE
            U, UNICODE: 根据Unicode字符集解析字符,这个标志影响 \w, \W, \b, \B
            X, VERBOSE: 为正则表达式添加注释

import re

res = re.findall("h\w+", "Hello World!", re.I)  # 忽略大小写
print(res)  # ['Hello']

res = re.findall(".+", "Hello\r\nWorld!", re.S)  # 忽略大小写
print(res)  # ['Hello\r\nWorld!']

s = """hello world!
Hello Echo!
this is Tom 
"""
res = re.findall("^h\w+", s, re.M | re.I)  # 可以匹配每一行的开头结尾
print(res)  # ['hello', 'hello']

pattern = """(?P<name>hello) # name组
\s+ # 空白字符
(world!) # 第二个分组
"""
res = re.findall(pattern, s, re.X)  # 为正则表达式添加注释
print(res)  # [('hello', 'world!')]

    10.re模块sub替换方法的高级用法

import re


def add(temp):
    str_num = temp.group()
    num = int(str_num) + 1
    return str(num)


ret = re.sub(r"\d+", add, "python = 997")
print(ret)  # python = 998

ret = re.sub(r"\d+", add, "python = 99")
print(ret)  # python = 100
    print(getAddress(port))

    11.正则匹配接口文档地址示例
        1.接口文档文件: 1.txt

RP/0/RSP0/CPU0:2_c-leaf-1#  show interfaces
Thu Sep  7 15:17:18.514 UTC

BVI1 is down, line protocol is down
  Interface state transitions: 0
  Hardware is Bridge-Group Virtual Interface, address is 10f3.116c.e6a7
  Internet address is 192.168.100.254/24
  MTU 1514 bytes, BW 10000000 Kbit (Max: 10000000 Kbit)
     reliability 255/255, txload 0/255, rxload 0/255
  Encapsulation ARPA,  loopback not set,
  ARP type ARPA, ARP timeout 04:00:00
  Last input never, output never
  Last clearing of "show interface" counters never
  5 minute input rate 0 bits/sec, 0 packets/sec
  5 minute output rate 0 bits/sec, 0 packets/sec
     0 packets input, 0 bytes, 0 total input drops
     0 drops for unrecognized upper-level protocol
     Received 0 broadcast packets, 0 multicast packets
     0 packets output, 0 bytes, 0 total output drops
     Output 0 broadcast packets, 0 multicast packets

TenGigE0/0/2/3 is administratively down, line protocol is administratively down
  Interface state transitions: 0
  Hardware is TenGigE, address is 10f3.114b.978f (bia 10f3.114b.978f)
  Layer 1 Transport Mode is LAN
  Internet address is Unknown
  MTU 1514 bytes, BW 10000000 Kbit (Max: 10000000 Kbit)
     reliability 255/255, txload 0/255, rxload 0/255
  Encapsulation ARPA,
  Full-duplex, 10000Mb/s, SR, link type is force-up
  output flow control is off, input flow control is off
  Carrier delay (up) is 10 msec
  loopback not set,
  Last input 8w2d, output never
  Last clearing of "show interface" counters never
  5 minute input rate 0 bits/sec, 0 packets/sec
  5 minute output rate 0 bits/sec, 0 packets/sec
     51 packets input, 3372 bytes, 0 total input drops
     0 drops for unrecognized upper-level protocol
     Received 0 broadcast packets, 51 multicast packets
              0 runts, 0 giants, 0 throttles, 0 parity
     0 input errors, 0 CRC, 0 frame, 0 overrun, 0 ignored, 0 abort
     0 packets output, 0 bytes, 0 total output drops
     Output 0 broadcast packets, 0 multicast packets
     0 output errors, 0 underruns, 0 applique, 0 resets
     0 output buffer failures, 0 output buffers swapped out
     0 carrier transitions

        2.脚本文件: demo1.py

import re
import sys


def getAddress(port):
    pattern = r'^\S+'
    f = open('1.txt', 'r')
    while True:
        data = ''
        for line in f:
            if line != '\n':
                data += line
            else:
                break
        if not data:
            break
        PORT = re.match(pattern, data).group()
        if port == PORT:
            pattern = r'address is (\S+)'
            addr = re.search(pattern, data).group(1)
            return addr
        else:
            continue


if __name__ == '__main__':
    # 运行方式: python3 demo1.py BVI1
    port = sys.argv[1]
    print(getAddress(port))

5.时间相关模块 time

    1.time模块概述:
        1.time模块常应用于转换时间格式和延时,如果年份小于100会自动转换为加上1900后的值
        2.UTC: 国际标准时间,DST: 阳光节约时间,也叫夏令时,夏令修正时间(-1, 0 or 1)
        3.导入语法: import time
        4.格式化时间字符串:
            %y: 两位数的年份表示(00-99)
            %Y: 四位数的年份表示(000-9999)
            %m: 月份(01-12)
            %d: 月内中的一天(0-31)
            %H: 24小时制小时数(0-23)
            %I: 12小时制小时数(01-12)
            %M: 分钟数(00=59)
            %S: 秒(00-59)
            %a: 本地简化星期名称
            %A: 本地完整星期名称
            %b: 本地简化的月份名称
            %B: 本地完整的月份名称
            %c: 本地相应的日期表示和时间表示
            %j: 年内的一天(001-366)
            %p: 本地A.M.或P.M.的等价符
            %U: 一年中的星期数(00-53)星期天为星期的开始
            %w: 星期(0-6),星期天为星期的开始,0代表星期一
            %W: 一年中的星期数(00-53)星期一为星期的开始
            %x: 本地相应的日期表示
            %X: 本地相应的时间表示
            %Z: 当前时区的名称
            %%: %号本身
        5.struct_time元组共有9个元素共九个元素:(年,月,日,时,分,秒,星期几,一年中第几天,是否是夏令时)

 索引  属性(Attribute) 值(Values)
0 tm_year(年) 比如2011
1 tm_mon(月) 1 - 12
2 tm_mday(日) 1 - 31
3 tm_hour(时) 0 - 23
4 tm_min(分) 0 - 59
5 tm_sec(秒) 0 - 60
6 tm_wday(星期几)  0 - 6(0表示周一) 
7  tm_yday(一年中的第几天)  1 - 366
8 tm_isdst(是否是夏令时) 默认为0

    2.模块名.属性

import time

# 夏令时时间与UTC时间差(秒为单位)
time.altzone  # -28800

# 夏令时校正时间
time.daylight  # 0

# 本地区时间与UTC时间差(秒为单位)
time.timezone  # -28800

# 时区名字的元组,第一个名字为未经夏令时修正的时区名,第二个名字为经夏令时修正后的时区名
time.tzname  # ('CST', 'CST')

    3.模块名.方法-取时间(time, localtime, gmtime)

import time

# time()取时间戳-->做计算
print(time.time())  # 1553274079.3324106秒-->1970年凌晨到现在的时间经过了多少秒

# localtime结构化时间-->当地时间
t = time.localtime()  # 默认参数time.time()
print(t)
"""执行结果
    time.struct_time(tm_year=2020, tm_mon=5, tm_mday=31, 
    tm_hour=11, tm_min=45, tm_sec=51, 
    tm_wday=6, tm_yday=152, tm_isdst=0)
"""
# 打印年
print(t.tm_year)  # 2020

# gmtime结构化时间-->UTC世界标准时间, 比中国时间慢8小时
print(time.gmtime())  # 格林时间
"""执行结果
    time.struct_time(tm_year=2020, tm_mon=5, tm_mday=31, 
    tm_hour=3, tm_min=48, tm_sec=16, 
    tm_wday=6, tm_yday=152, tm_isdst=0)
"""

    4.模块名.方法-格式转换(localtime, gmtime, mktime, strftime strptime, asctime, ctime)

import time

# 时间戳转结构化时间
#time.gmtime(时间戳): UTC时间,与英国伦敦当地时间一致
#time.localtime(时间戳): 当地时间,在北京执行这个方法与UTC时间相差8小时,UTC时间+8小时 = 北京时间
time.gmtime(1500000000)
"""执行结果
    time.struct_time(tm_year=2017, tm_mon=7, tm_mday=14, tm_hour=2, tm_min=40, 
    tm_sec=0, tm_wday=4, tm_yday=195, tm_isdst=0)
"""
time.localtime(1500000000)
"""执行结果
    time.struct_time(tm_year=2017, tm_mon=7, tm_mday=14, tm_hour=10, tm_min=40, 
    tm_sec=0, tm_wday=4, tm_yday=195, tm_isdst=0)
"""

# mktime结构化时间转换成时间戳
print(time.mktime(t))
time.mktime(time.localtime(15000))  # 15000.0

# strftime结构化时间转换成字符串时间
# Y年 m月 d日 X时分秒 t结构化时间
print(time.strftime("%Y-%m-%d %X", t))  # 2020-05-31 11:45:51

# strptime将字符串时间转换成结构化时间
print(time.strptime("2019:03:23:01:26:11", "%Y:%m:%d:%X"))
"""print(time.strptime("2019:03:23:01:26:11", "%Y:%m:%d:%X"))执行结果
    time.struct_time(tm_year=2019, tm_mon=3, tm_mday=23, 
    tm_hour=1, tm_min=26, tm_sec=11, 
    tm_wday=5, tm_yday=82, tm_isdst=-1)
"""

# asctime()将结构化时间转换成固定的字符串表达方式-->默认参数取当前结构化时间
#  周月日时分秒年
print(time.asctime())  # Sun May 31 11:52:22 2020

# ctime()将时间戳时间转换成固定的字符串表达方式-->默认参数取当前时间戳
#  周月日时分秒年
print(time.ctime())  # Sun May 31 11:52:48 2020

    5.模块名.方法-时间延时(sleep)

import time

# sleep()线程推迟指定时间运行,单位秒
time.sleep(1)  # 睡一秒

    6.模块名.方法-计算时间差(mktime, gmtime)

import time

true_time = time.mktime(time.strptime("2017-09-11 08:30:00", "%Y-%m-%d %H:%M:%S"))
time_now = time.mktime(time.strptime("2017-09-12 11:00:00", "%Y-%m-%d %H:%M:%S"))
dif_time = time_now - true_time
struct_time = time.gmtime(dif_time)
print("过去了%d年%d月%d天%d小时%d分钟%d秒" % (struct_time.tm_year - 1970,
                                   struct_time.tm_mon - 1,
                                   struct_time.tm_mday - 1,
                                   struct_time.tm_hour,
                                   struct_time.tm_min,
                                   struct_time.tm_sec))

6.时间相关模块 datetime

    1.模块名.方法-取时间(now, utcnow)

from datetime import datetime

# 获取当前本地时间
a = datetime.now()
print("当前日期:", a)  # 当前日期: 2020-06-23 07:13:55.317040

# 获取当前世界时间
b = datetime.utcnow()
print("世界时间:", b)  # 世界时间: 2020-06-22 23:13:55.317154

# 用指定日期创建datetime类型时间
c = datetime(2018, 5, 27, 16, 30)
print("指定日期:", c)  # 指定日期: 2018-05-27 16:30:00

    2.模块名.方法-类型转换(strptime, strftime)

from datetime import datetime

# 字符串转换成datetime类型
d = datetime.strptime("2018/9/30", "%Y/%m/%d")
print(d)  # 2018-09-30 00:00:00
e = datetime.strptime("2018年9月30日星期六", "%Y年%m月%d日星期六")
print(e)  # 2018-09-30 00:00:00
f = datetime.strptime("2018年9月30日星期六8时42分24秒", "%Y年%m月%d日星期六%H时%M分%S秒")
print(f)  # 2018-09-30 08:42:24
g = datetime.strptime("9/30/2018", "%m/%d/%Y")
print(g)  # 2018-09-30 00:00:00
h = datetime.strptime("9/30/2018 8:42:50 ", "%m/%d/%Y %H:%M:%S ")
print(h)  # 2018-09-30 08:42:50

# datetime类型转换成字符串
i = datetime(2018, 9, 28, 10, 3, 43)
print(i.strftime("%Y年%m月%d日%A,%H时%M分%S秒"))  # 2018年09月28日Friday,10时03分43秒
j = datetime(2018, 9, 30, 10, 3, 43)
print(j.strftime("%A,%B %d,%Y"))  # Sunday,September 30,2018
k = datetime(2018, 9, 30, 9, 22, 17)
print(k.strftime("%m/%d/%Y %I:%M:%S%p"))  # 09/30/2018 09:22:17AM
l = datetime(2018, 9, 30)
print(l.strftime("%B %d,%Y"))  # September 30,2018

    3.模块名.方法-时间截取(strftime)

from datetime import datetime

m = datetime.now()  # 获取当前系统时间
print(m.strftime("今天是%Y年%m月%d日"))  # 今天是2020年06月23日
print(m.strftime("今天是这周的第%w天"))  # 今天是这周的第2天
print(m.strftime("今天是今年的第%j天"))  # 今天是今年的第175天
print(m.strftime("今周是今年的第%W周"))  # 今周是今年的第25周
print(m.strftime("今天是当月的第%d天"))  # 今天是当月的第23天

    4.时间加减和替换

import datetime

print(datetime.datetime.now())  # 2020-06-22 21:08:43.500433
# 时间戳直接转成日期格式
print(datetime.date.fromtimestamp(time.time()))  # 2020-06-22

# 返回当前系统时间
print(datetime.datetime.now())  #  2020-06-22 21:08:43.500485
# 当前时间+3天
print(datetime.datetime.now() + datetime.timedelta(3))  # 2020-06-25 21:08:43.500491
#  当前时间-3天
print(datetime.datetime.now() + datetime.timedelta(-3))  # 2020-06-19 21:08:43.500503
# 当前时间+3小时 
print(datetime.datetime.now() + datetime.timedelta(hours=3))  # 2020-06-23 00:08:43.500508
# 当前时间+30分
print(datetime.datetime.now() + datetime.timedelta(minutes=30))  # 2020-06-22 21:38:43.500516

#  时间替换
c_time = datetime.datetime.now()
print(c_time.replace(minute=3, hour=2))  # 2020-06-22 02:03:43.500522

7.序列化模块 json

    1.json模块概述
        json用于字符串和Python数据类型间进行转换,set数据类型不能被dump/dumps,json格式中的字符串只能是""
        导入语法: import json

    2.dump方法和load方法

import json

# json格式的key必须是字符串数据类型,如果是数字为key,那么dump之后会强行转成字符串数据类型
dic = {1:2,3:4}
str_dic = json.dump(dic)  # 转换成所有语言都支持的json的字符串
print(str_dic)  # {"1": 2, "3": 4}
new_dic = json.load(str_dic)  # # 将json处理的字符串还原原来的数据类型
print(new_dic)  # {'1': 2, '3': 4}

# 单次dump数据到文件里,单次从文件中load出来
f = open('json_file', 'w')
dic = {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'}
json.dump(dic, f)  # dump方法接收一个文件句柄,直接将字典转换成json字符串写入文件
f.close()
f = open('json_file')
dic2 = json.load(f)  # load方法接收一个文件句柄,直接将文件中的json字符串转换成数据结构返回
f.close()
print(type(dic2), dic2)  # <class 'dict'> {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'}

# 对列表的dump
lst = ['aaa', 123, 'bbb', 12.456]
with open('json_demo', 'w') as f:
    json.dump(lst, f)
with open('json_demo') as f:
    ret = json.load(f)
    print(ret)  # ['aaa', 123, 'bbb', 12.456]

# 能不能多次dump数据到文件里,可以多次dump但是不能load出来
dic = {'abc': (1, 2, 3)}
lst = ['aaa', 123, 'bbb', 12.456]
with open('json_demo', 'w') as f:
    json.dump(lst, f)
    json.dump(dic, f)
with open('json_demo') as f:
    ret = json.load(f)  # 抛出异常: json.decoder.JSONDecodeError
    print(ret)

    3.dumps方法和loads方法

import json

# json对元组做value的字典会把元组强制转换成列表
dic = {'abc':(1,2,3)}
str_dic = json.dumps(dic)
print(str_dic)  # {"abc": [1, 2, 3]}
new_dic = json.loads(str_dic)
print(new_dic)  # {'abc': [1, 2, 3]}

# json不支持元组做key操作
dic = {(1,2,3):'abc'}
str_dic = json.dumps(dic)  # 报错

# 用dumps将多个数据写进入文件
dic = {'abc': (1, 2, 3)}
lst = ['aaa', 123, 'bbb', 12.456]
with open('json_demo', 'w') as f:
    str_lst = json.dumps(lst)
    str_dic = json.dumps(dic)
    f.write(str_lst + '\n')
    f.write(str_dic + '\n')

with open('json_demo') as f:
    for line in f:
        ret = json.loads(line)
        print(ret)  # ['aaa', 123, 'bbb', 12.456] {'abc': [1, 2, 3]} 

# 序列化: 将一个字典转换成一个字符串,json转换完的字符串类型的字典中的字符串是由""表示的
dic = {'k1':'v1','k2':'v2','k3':'v3'}
str_dic = json.dumps(dic)  
print(type(str_dic),str_dic)  # <class 'str'> {"k3": "v3", "k1": "v1", "k2": "v2"}

# 反序列化: 将一个字符串格式的字典转换成一个字典,json处理的字符串类型的字典中的字符串必须由""表示
dic2 = json.loads(str_dic)
print(type(dic2),dic2)  # <class 'dict'> {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'}

# 处理嵌套的数据类型
list_dic = [1,['a','b','c'],3,{'k1':'v1','k2':'v2'}]
str_dic = json.dumps(list_dic)
print(type(str_dic),str_dic)  # <class 'str'> [1, ["a", "b", "c"], 3, {"k1": "v1", "k2": "v2"}]
list_dic2 = json.loads(str_dic)
print(type(list_dic2),list_dic2)  # <class 'list'> [1, ['a', 'b', 'c'], 3, {'k1': 'v1', 'k2': 'v2'}]

    4.其他参数说明
        Skipkeys
            默认值是False,dict的keys内的数据不是python的基本类型(str,unicode,int,long,float,bool,None)
            设置为False时,会报TypeError的错误,此时设置成True,则会跳过这类key
        ensure_ascii
            当它为True的时候,所有非ASCII码字符显示为"\uXXXX"序列,只需在dump时将ensure_ascii设置为False即可,
            此时存入json的中文即可正常显示
        indent
            应该是一个非负的整型,如果是0就是顶格分行显示,如果为空就是一行最紧凑显示,否则会换行且按照indent的数值显示前面的空白分行显示,
            这样打印出来的json数据也叫pretty-printed json
        separators
            分隔符,实际上是(item_separator, dict_separator)的一个元组,默认的就是(',', ':'),这表示dictionary内keys之间用','隔开,
            而KEY和value之间用':'隔开
        sort_keys: 将数据根据keys的值进行排序

import json

f = open('file', 'w')
json.dump({'国籍': '中国'}, f)
ret = json.dumps({'国籍': '中国'})
f.write(ret + '\n')
json.dump({'国籍': '美国'},f, ensure_ascii=False)
ret = json.dumps({'国籍': '美国'}, ensure_ascii=False)
f.write(ret + '\n')
f.close()

    5.json格式化输出

# 不推荐使用,是为了用户看的更方便,但是会相对浪费存储空间
import json

data = {'username': ['汤姆猫', '傻傻的'], 'sex': 'male', 'age': 16}
jn_dic = json.dumps(data,sort_keys=True, indent=2, separators=(',', ':'), ensure_ascii=False)
print(jn_dic)
"""执行结果
    {
      "age":16,
      "sex":"male",
      "username":[
        "汤姆猫",
        "傻傻的"
      ]
    }
"""

8.序列化模块 pickle

    1.pickle模块概述
        pickle 用于python特有的类型和python的数据类型间进行转换,对于多次dump/load的操作做了良好的处理
        pickle 将数据转换成字节,还支持函数和类的转换,对于对象的序列化需要这个对象对应的类在内存中
        pickle 的dump结果是bytes,dump用的f文件句柄需要以wb的形式打开,load所用的f是'rb'模式
        导入语法: import pickle

    2.dump方法和load方法

# pickle模块来存储每个学员的对象
import pickle

with open('pickle_demo','wb') as f:
    pickle.dump({'k1': 'v1'}, f)
    pickle.dump({'k11': 'v1'}, f)
    pickle.dump({'k11': 'v1'}, f)
    pickle.dump({'k12': [1,2,3]}, f)
    pickle.dump(['k1','v1','l1'], f)

with open('pickle_demo','rb') as f:
    while True:
        try:
            print(pickle.load(f))
        except EOFError:
            break
"""执行结果
    {'k1': 'v1'}
    {'k11': 'v1'}
    {'k11': 'v1'}
    {'k12': [1, 2, 3]}
    ['k1', 'v1', 'l1']
"""

# pickle支持几乎所有对象的
import pickle

class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age


Tom = Student('Tom',13)
with open('pickle_demo', 'wb') as f:
    pickle.dump(Tom,f)
with open('pickle_demo', 'rb') as f:
    Cat = pickle.load(f)
    print(Cat.name)  # Tom
    print(Cat.age)  # 13

    3.dumps方法和loads方法

import pickle

dic1 = {"name": "coco"}
data2 = pickle.dumps(dic1)  # 转换成所有语言都支持的pickle的bytes
print(data2)  # b'\x80\x03}q\x00X\x04\x00\x00\x00nameq\x01X\x04\x00\x00\x00cocoq\x02s.'
print(type(data2))  # <class 'bytes'>
f1 = open("test3", "wb")
# data = pickle.dump(dic1, f)  # 直接转化写入文件
f1.write(data2)
f1.close()

f1_read = open("test3", "rb")
data3 = pickle.loads(f1_read.read())  # 将pickle处理的bytes还原原来的数据类型
# data3 = pickle.load(f)  # 直接读取还原
print(data3)  # {'name': 'coco'}
print(type(data3))  # <class 'dict'>
f1_read.close()

9.序列化读文件模块 shelve

    1.shelve模块概述:
        文件改动的比较少,读文件的操作比较多,且大部分读取都需要基于某个key获得某个value时推荐使用shelve模块
        导入语法: import shelve

import shelve

f = shelve.open(r"shelve.txt")  # 生成一个空文本
f["stu1_info"] = {"name": "coco", "age": "26"}  # 将字典放入文本
f["stu2_info"] = {"name": "angels", "age": "18"}

print(f.get("stu1_info")["name"])   # coco
print(f.get("stu2_info")["age"])  # 18
f.close()

10.算法摘要模块 hashlib

import hashlib

# md5
# md5是一个算法,32位的字符串,每个字符都是一个十六进制
# md5算法 效率快 算法相对简单
obj = hashlib.md5("ssasdf".encode(encoding="utf8"))  # 自定义加盐
obj.update("coco".encode(encoding="utf8"))  # 原生md5加密
print(obj.hexdigest())  # 516dacada2fea0112265e3a474dee5fe

# sha256
obj = hashlib.sha256("ssasdf".encode(encoding="utf8"))  # 自定义加盐
obj.update("coco".encode(encoding="utf8"))  # 原生md5加密
print(obj.hexdigest())  # 577cce053410c4bf7ccee892b3d92c55f20c56b773276a326777a4535a021909

# sha1也是一个算法,40位的字符串,每个字符都是一个十六进制
# 算法相对复杂 计算速度也慢
s1 = "fadfasvfdfsf"
sha1_obj = hashlib.sha1()
sha1_obj.update(s1.encode('utf-8'))
res = sha1_obj.hexdigest()
print(res,len(res), type(res))  # a794b78d12fd18898d65e1b4ff320f44f7dbe2a9 40 <class 'str'>

# 动态加盐
username = input('username : ')
passwd = input('password : ')
md5obj = hashlib.md5(username.encode('utf-8'))
md5obj.update(passwd.encode('utf-8'))
print(md5obj.hexdigest())  # ee838c58e5bb3c9e687065edd0ec454f

# 文件的一致性校验
md5_obj = hashlib.md5()
with open('5.序列化模块_shelve.py', 'rb') as f:
    md5_obj.update(f.read())
    ret1 = md5_obj.hexdigest()

md5_obj = hashlib.md5()
with open('5.序列化模块_shelve.py.bak', 'rb') as f:
    md5_obj.update(f.read())
    ret2 = md5_obj.hexdigest()
print(ret1,ret2)

# 大文件的一致性校验
md5_obj = hashlib.md5()
with open('5.序列化模块_shelve.py.bak', 'rb') as f:
    md5_obj.update(f.read(10240))
    # 循环 循环的读取文件内容
    # 循环的来update
print(md5_obj.hexdigest())

# 模拟撞库破解密码
    import hashlib

    passwds = [
        'alex3714',
        'alex1313',
        'alex94139413',
        'alex123456',
        '123456alex',
        'a123lex',
    ]


    def make_passwd_dic(passwds):
        dic = {}
        for passwd in passwds:
            m = hashlib.md5()
            m.update(passwd.encode('utf-8'))
            dic[passwd] = m.hexdigest()
        return dic


    def break_code(cryptograph, passwd_dic):
        for k, v in passwd_dic.items():
            if v == cryptograph:
                print('密码是===>\033[46m%s\033[0m' % k)


    cryptograph = 'aee949757a2e698417463d47acac93df'
    break_code(cryptograph, make_passwd_dic(passwds))

11.日志模块 logging

    1.日志从低到高的五个级别
        DEBUG: 调试模式,详细的信息,通常只出现在诊断问题上
        INFO: 基础信息,确认一切按预期运行
        WARNING: 警告,一个迹象表明一些意想不到的事情发生了,或表明一些问题在不久的将来例如磁盘空间低,这个软件还能按预期工作
        ERROR: 错误,更严重的问题,软件没能执行一些功能
        CRITICAL: 严重错误: 一个严重的错误,这表明程序本身可能无法继续运行

    2.配置日志的两种方式

        1.basicConfig定义日志

import logging

logging.basicConfig(
    level=logging.DEBUG,  # 设置显示日志级别
    filename="./logger.log",  # 设置写出日志路径
    filemode="w",  # 覆盖写入
    format="%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s"  # 设置写出格式
)

# 日志
logging.debug("debug message")  # 调试模式
logging.info("info message")  # 基础信息
logging.warning("warning massage")  # 警告
logging.error("error massage")  # 错误
logging.critical("critical massage")  # 严重错误
"""执行结果: 当前路径下生成logger.log文件
    2020-07-11 23:12:49,453 - test_log1.py[line:12] - DEBUG: debug message
    2020-07-11 23:12:49,453 - test_log1.py[line:13] - INFO: info message
    2020-07-11 23:12:49,453 - test_log1.py[line:14] - WARNING: warning massage
    2020-07-11 23:12:49,453 - test_log1.py[line:15] - ERROR: error massage
    2020-07-11 23:12:49,454 - test_log1.py[line:16] - CRITICAL: critical massage
"""

        2.getLogger创建对象定义日志

def set_logger():
    # 第一步,创建一个logger
    set_log = logging.getLogger()  # 创建一个logger对象
    set_log.setLevel(logging.INFO)  # 设置Log等级总开关,默认的是WARNING

    # 第二步,创建一个handler文件管理操作符,用于写入日志文件
    logfile = './log.txt'
    fh = logging.FileHandler(logfile, mode='a')  # open的打开模式这里可以进行参考
    fh.setLevel(logging.DEBUG)  # 输出到file的log等级的开关

    # 第三步,再创建一个handler屏幕管理操作符,用于输出到控制台
    ch = logging.StreamHandler()
    ch.setLevel(logging.WARNING)  # 输出到console的log等级的开关

    # 第四步,定义handler的输出格式
    formatter = logging.Formatter("%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s")
    fh.setFormatter(formatter)  # 文件管理操作符 绑定一个 格式
    ch.setFormatter(formatter)  # 屏幕管理操作符 绑定一个 格式

    # 第五步,将logger添加到handler里面
    set_log.addHandler(fh)  # logger对象 绑定 文件管理操作符
    set_log.addHandler(ch)  # logger对象 绑定 屏幕管理操作符

    return set_log


# 日志
logger = set_logger()
logger.debug('这是 logger debug message')
logger.info('这是 logger info message')
logger.warning('这是 logger warning message')
logger.error('这是 logger error message')
logger.critical('这是 logger critical message')
"""
    2020-07-11 23:10:08,934 - test_log2.py[line:34] - INFO: 这是 logger info message
    2020-07-11 23:10:08,934 - test_log2.py[line:35] - WARNING: 这是 logger warning message
    2020-07-11 23:10:08,934 - test_log2.py[line:36] - ERROR: 这是 logger error message
    2020-07-11 23:10:08,934 - test_log2.py[line:37] - CRITICAL: 这是 logger critical message
"""

    2.logging.basicConfig()函数中可通过具体参数来更改logging模块默认行为,可用参数如下
        filename: 用指定的文件名创建FiledHandler,这样日志会被存储在指定的文件中
        filemode: 文件打开方式,在指定了filename时使用这个参数,默认值为"a"还可指定为"w"
        format: 指定handler使用的日志显示格式
        datefmt: 指定日期时间格式
        level: 设置rootlogger(后边会讲解具体概念)的日志级别
        stream: 用指定的stream创建StreamHandler
            可以指定输出到sys.stderr,sys.stdout或者文件(f = open(‘test.log’, ’w’))
            默认为sys.stderr,若同时列出了filename和stream两个参数,则stream参数会被忽略
        常用的格式: format = '%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s'

    3.format参数中可能用到的格式化串
        %(name)s: Logger的名字
        %(levelno)s: 数字形式的日志级别
        %(levelname)s: 文本形式的日志级别
        %(pathname)s: 调用日志输出函数的模块的完整路径名,可能没有,其实就是sys.argv[0]
        %(filename)s: 调用日志输出函数的模块的文件名
        %(module)s: 调用日志输出函数的模块名
        %(funcName)s: 调用日志输出函数的函数名
        %(lineno)d: 调用日志输出函数的语句所在的代码行行号
        %(created)f: 当前时间,用UNIX标准的表示时间的浮 点数表示
        %(relativeCreated)d: 输出日志信息时的,自Logger创建以 来的毫秒数
        %(asctime)s: 字符串形式的当前时间,默认格式是 "2003-07-08 16:49:45,896" 逗号后面的是毫秒
        %(thread)d: 线程ID,可能没有
        %(threadName)s: 线程名,可能没有
        %(process)d: 进程ID,可能没有
        %(message)s: 用户输出的消息即日志信息

    4.日志切割

import logging
import time
from logging import handlers

sh = logging.StreamHandler()
rh = handlers.RotatingFileHandler('myapp.log', maxBytes=1024, backupCount=5)
fh = handlers.TimedRotatingFileHandler(filename='x2.log', when='s', interval=5, encoding='utf-8')
logging.basicConfig(
    format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S %p',
    handlers=[fh, sh, rh],
    level=logging.ERROR
)

for i in range(1, 100000):
    time.sleep(1)
    logging.error('KeyboardInterrupt error %s' % str(i))

    5.django中的日志配置

# logging_config.py
LOGGING = {
    'version': 1,  # 保留字
    'disable_existing_loggers': False,  # 禁用已经存在的logger实例
    'formatters': {
        # 详细的日志格式
        'standard': {
            'format': '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s]''[%(filename)s:%(lineno)d]'
                      '[%(levelname)s][%(message)s]'
        },
        # 简单的日志格式
        'simple': {
            'format': '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'
        },
        # 定义一个特殊的日志格式
        'collect': {
            'format': '%(message)s'
        }
    },
    # 过滤器
    'filters': {
        'require_debug_true': {
            '()': 'django.utils.log.RequireDebugTrue',
        },
    },
    # 处理器,定义具体处理日志的方式
    'handlers': {
        # 打印到终端的日志
        'console': {
            'level': 'DEBUG',
            'filters': ['require_debug_true'],  # 只有在Django debug为True时才在屏幕打印日志
            'class': 'logging.StreamHandler',
            'formatter': 'simple'
        },
        # 打印到文件的日志,收集info及以上的日志
        'default': {
            'level': 'INFO',
            'class': 'logging.handlers.RotatingFileHandler',  # 保存到文件,自动切
            'filename': os.path.join(BASE_LOG_DIR, "xxx_info.log"),  # 日志文件
            'maxBytes': 1024 * 1024 * 5,  # 日志大小 5M
            'backupCount': 3,  # 最多备份几个
            'formatter': 'standard',  # 输出格式
            'encoding': 'utf-8',
        },
        # 打印到文件的日志:收集错误及以上的日志
        'error': {
            'level': 'ERROR',
            'class': 'logging.handlers.RotatingFileHandler',  # 保存到文件,自动切
            'filename': os.path.join(BASE_LOG_DIR, "xxx_err.log"),  # 日志文件
            'maxBytes': 1024 * 1024 * 5,  # 日志大小 5M
            'backupCount': 5,
            'formatter': 'standard',
            'encoding': 'utf-8',
        },
        # 打印到文件的日志
        'collect': {
            'level': 'INFO',
            'class': 'logging.handlers.RotatingFileHandler',  # 保存到文件,自动切
            'filename': os.path.join(BASE_LOG_DIR, "xxx_collect.log"),
            'maxBytes': 1024 * 1024 * 5,  # 日志大小 5M
            'backupCount': 5,
            'formatter': 'collect',
            'encoding': "utf-8"
        }
    },
    'loggers': {
        # logging.getLogger(__name__)拿到的logger配置
        '': {
            'handlers': ['default', 'console', 'error'],
            'level': 'DEBUG',
            'propagate': True,  # 向不向更高级别的logger传递
        },
        # logging.getLogger('collect')拿到的logger配置
        'collect': {
            'handlers': ['console', 'collect'],
            'level': 'INFO',
        }
    },
}

# 用法:拿到俩个logger
logger = logging.getLogger(__name__)  # 线上正常的日志
collect_logger = logging.getLogger("collect")  # 为领导们单独定制领导们看的日志

12.配置文件模块 configparser

import configparser

config = configparser.ConfigParser()

config["DEFAULT"] = {
    "Sever": "45",
    "Compression": "yes",
    "CompressionLevel": "9"
}

config["bt.org"] = {}
config["bt.org"]["User"] = "coco"

config["sever.com"] = {}
top = config["sever.com"]
top["Host Ip"] = "127.0.0.1"
top["Host Port"] = "8080"

with open("example.ini", "w") as configfile:
    config.write(configfile)

# 查配置文件
config.read("example.ini")
print(config.sections())  # 读除默认块以外的块名['bt.org', 'sever.com']
print(config["bt.org"]["user"])  # coco
for key in config:
    print(key)

print(config.options("bt.org"))  # ['user', 'sever', 'compression', 'compressionlevel']
print(config.items("bt.org"))  # [('sever', '45'), ('compression', 'yes'), ('compressionlevel', '9'), ('user', 'coco')]
print(config.get("bt.org", "user"))  # coco

# 添加,修改,删除
config.add_section("yun")  # 添加块
config.set("yun", "k1", "11")  # 添加键值对,同名覆盖即修改
config.remove_option("sever.com", "host port")  # 删除块下的某个键值对
config.remove_section("sever.com")  # 删除块及块里面的的所有键值对

config.write(open("i.cfg"), "w")
配置文件如下:
    # 注释1
    # 注释2

    [section1]
    k1 = v1
    k2:v2
    user=egon
    age=18
    is_admin=true
    salary=31

    [section2]
    k1 = v1
读取配置文件:
    import configparser

    config = configparser.ConfigParser()
    config.read('a.cfg')

    # 查看所有的标题
    res = config.sections()  # ['section1', 'section2']
    print(res)

    # 查看标题section1下所有key=value的key
    options = config.options('section1')
    print(options)  # ['k1', 'k2', 'user', 'age', 'is_admin', 'salary']

    # 查看标题section1下所有key=value的(key,value)格式
    item_list = config.items('section1')
    print(item_list)
    # [('k1', 'v1'), ('k2', 'v2'), ('user', 'egon'), ('age', '18'), ('is_admin', 'true'), ('salary', '31')]

    # 查看标题section1下user的值=>字符串格式
    val = config.get('section1', 'user')
    print(val)  # egon

    # 查看标题section1下age的值=>整数格式
    val1 = config.getint('section1', 'age')
    print(val1)  # 18

    # 查看标题section1下is_admin的值=>布尔值格式
    val2 = config.getboolean('section1', 'is_admin')
    print(val2)  # True

    # 查看标题section1下salary的值=>浮点型格式
    val3 = config.getfloat('section1', 'salary')
    print(val3)  # 31.0
改写配置文件:
    import configparser

    config = configparser.ConfigParser()
    config.read('a.cfg', encoding='utf-8')

    # 删除整个标题section2
    config.remove_section('section2')

    # 删除标题section1下的某个k1和k2
    config.remove_option('section1', 'k1')
    config.remove_option('section1', 'k2')

    # 判断是否存在某个标题
    print(config.has_section('section1'))

    # 判断标题section1下是否有user
    print(config.has_option('section1', ''))

    # 添加一个标题
    config.add_section('egon')

    # 在标题egon下添加name=egon,age=18的配置
    config.set('egon', 'name', 'egon')
    # config.set('egon', 'age', 18)  # 报错,必须是字符串

    # 最后将修改的内容写入文件,完成最终的修改
    config.write(open('a.cfg', 'w'))
添加ini文档
    import configparser

    config = configparser.ConfigParser()
    config["DEFAULT"] = {'ServerAliveInterval': '45',
                         'Compression': 'yes',
                         'CompressionLevel': '9'}

    config['bitbucket.org'] = {}
    config['bitbucket.org']['User'] = 'hg'
    config['topsecret.server.com'] = {}
    topsecret = config['topsecret.server.com']
    topsecret['Host Port'] = '50022'  # mutates the parser
    topsecret['ForwardX11'] = 'no'  # same here
    config['DEFAULT']['ForwardX11'] = 'yes'
    with open('example.ini', 'w') as configfile:
        config.write(configfile)

13.标记语言模块 xml

import xml.etree.ElementTree as ET  # as 取别名

"""xml_lesson文件
    <?xml version="1.0"?>
    <data>
        <country name="Liechtenstein">
            <rank updated="yes">2</rank>
            <year>2008</year>
            <gdppc>141100</gdppc>
            <neighbor name="Austria" direction="E"/>
            <neighbor name="Switzerland" direction="W"/>
        </country>
        <country name="Singapore">
            <rank updated="yes">5</rank>
            <year>2011</year>
            <gdppc>59900</gdppc>
            <neighbor name="Malaysia" direction="N"/>
        </country>
        <country name="Panama">
            <rank updated="yes">69</rank>
            <year>2011</year>
            <gdppc>13600</gdppc>
            <neighbor name="Costa Rica" direction="W"/>
            <neighbor name="Colombia" direction="E"/>
        </country>
    </data>
"""
tree = ET.parse("xml_lesson")  # parse解析xml,返回一个解析对象
root = tree.getroot()  # getroot 取根节点
print(root.tag)  # tag 拿到根节点的标签名

# 遍历xml文档
for child in root:
    print(child.tag, child.attrib)  # tag标签名,attrib标签属性
    for i in child:
        print(i.tag, i.text)  # text标签的内容

# 只遍历year节点
for node in root.iter("year"):  # iter指定拿root根下的某个节点
    print(node.tag, node.text)

# 修改
for node in root.iter("year"):
    new_year = int(node.text) + 1  # 修改year标签内容
    node.text = str(new_year)  # 重新赋值修改内容
    node.set("updated", "yes")  # 为year标签添加属性
tree.write("xml_lesson")  # 把修改后内容从新写一个文件,同名则覆盖原文件

# 删除
for country in root.findall("country"):  # findall 找root的所有country标签
    rank = int(country.find("rank").text)  # find 找country下的rank标签
    if rank >= 50:
        root.remove(country)
tree.write("xml_output")  # 把修改后内容从新写一个文件,同名则覆盖原文件

# 创建一个xml
new_xml = ET.Element("namelist")  # Element 创建根节点
name = ET.SubElement(new_xml, "name", attrib={"enrolled": "yes"})
age = ET.SubElement(name, "age", attrib={"checked": "no"})
sex = ET.SubElement(name, "sex")
sex.text = "26"

et = ET.ElementTree(new_xml)  # 生成文档对象
et.write("xml_text.xml", encoding="utf-8", xml_declaration=True)  # 写出到文档
ET.dump(new_xml)  # 打印生成格式

14.数据类型模块 collections

1.模块概述: Python在内置数据类型的基础上, collections模块还提供了几个额外的数据类型

        1.namedtuple: 生成可以使用名字来访问元素内容的tuple
        2.deque: 双端队列,可以快速的从另外一侧追加和推出对象
        3.Counter: 计数器,主要用来计数
        4.OrderedDict: 有序字典,在Python3.7之后的版本字典增加有序的特性
        5.defaultdict: 带有默认值的字典

2.元祖的扩展 namedtuple

# 用来表示一个点的二维坐标
from collections import namedtuple

Point = namedtuple("Point", ["x", "y"])
p = Point(1, 2)
print(p.x, p.y)  # 1, 2
# 用坐标和半径表示一个圆
from collections import namedtuple

# namedtuple("名称", [属性list]):
Circle = namedtuple("Circle", ["x", "y", "r"])

3.双端队列 deque

        deque模块概述:
            1.使用list存储数据时,按索引访问元素快插入和删除元素慢,因为list是线性存储,数据量大的时候,插入和删除效率很低
            2.deque是为了高效实现插入和删除操作的双向列表,适合用于队列和栈
            3.deque实现了: append(), pop(), appendleft(), popleft(), 可以非常高效地往头部添加或删除元素
            4.在insert remove的时候 deque的平均效率要高于列表, 列表根据索引查看某个值的效率要高于deque
            5.导入语法: from collections import deque

from collections import deque

q = deque(["a", "b", "c"])
q.append("x")
q.appendleft("y")
print(q)  # deque(["y", "a", "b", "c", "x"])
from collections import deque

dq = deque()
dq.append(2)
dq.append(5)
dq.appendleft("a")
dq.appendleft("b")
print(dq)  # deque(["b", "a", 2, 5])

# print(dq.pop())  # 5
# print(dq)  # deque(["b", "a", 2])
# print(dq.popleft())  # b
# print(dq)  # deque(["a", 2])

print(dq.remove("a"))  # None
print(dq.insert(2, "123"))  # None
print(dq)  # deque(["b", 2, "123", 5])

4.计数器 Counter

    Counter模块概述:
        1.Counter类的目的是用来跟踪值出现的次数,它是一个无序的容器类型
        2.以字典的键值对形式存储,其中元素作为key,其计数作为value,计数值可以是任意的Interger(包括0和负数)
        3.导入语法: from collections import Counter

from collections import Counter

c = Counter("abcdeabcdabcaba")
print(c)  # Counter({"a": 5, "b": 4, "c": 3, "d": 2, "e": 1})

5.有序字典 OrderedDict

# 保持字典Key的顺序
from collections import OrderedDict

d = dict([("a", 1), ("b", 2), ("c", 3)])
print(d)  # dict的Key是无序的 {"a": 1, "c": 3, "b": 2}

od = OrderedDict([("a", 1), ("b", 2), ("c", 3)])
print(od)  # OrderedDict的Key是有序的 OrderedDict([("a", 1), ("b", 2), ("c", 3)])

6.带有默认值的字典 defaultdict

    defaultdict字典概述:
        1.使用dict时如果引用的Key不存在就会抛出KeyError,如果希望key不存在时返回一个默认值就可以用defaultdict
        2.导入语法: from collections import defaultdict

# 将集合中所有大于 66 的值保存至字典的第一个key中,将小于 66 的值保存至第二个key的值中
from collections import defaultdict

values = [11, 22, 33, 44, 55, 66, 77, 88, 99, 90]
my_dict = defaultdict(list)
for value in values:
    if value > 66:
        my_dict["k1"].append(value)
    else:
        my_dict["k2"].append(value)
# 不使用默认字典实现方法
values = [11, 22, 33, 44, 55, 66, 77, 88, 99, 90]
my_dict = {}
for value in values:
    if value > 66:
        if my_dict.has_key("k1"):
            my_dict["k1"].append(value)
        else:
            my_dict["k1"] = [value]
    else:
        if my_dict.has_key("k2"):
            my_dict["k2"].append(value)
        else:
            my_dict["k2"] = [value]
from collections import defaultdict

dd = defaultdict(lambda: "N/A")
dd["key1"] = "abc"
dd["key1"]  # key1存在返回'abc'
dd["key2"]  # key2不存在,返回默认值'1.1N/A'

15.高级的文件,文件夹,压缩包处理模块 shutil

    1.shutil模块概述:
        1.shutil模块拥有许多文件,文件夹操作的功能,包括复制,移动,重命名,删除,压缩等
        2.导入语法: import shutil

    2.文件处理

# 将文件内容拷贝到另一个文件中
shutil.copyfileobj(open('old.xml', 'r'), open('new.xml', 'w'))

# 拷贝文件
shutil.copyfile('f1.log', 'f2.log')  # 目标文件无需存在

# 仅拷贝权限
shutil.copymode('f1.log', 'f2.log')  # 目标文件必须存在,内容,组用户均不变

# 仅拷贝状态的信息,包括: mode bits, atime, mtime, flags
shutil.copystat('f1.log', 'f2.log')  # 目标文件必须存在

# 拷贝文件和权限
shutil.copy('f1.log', 'f2.log')

# 拷贝文件和状态信息
shutil.copy2('f1.log', 'f2.log')

    3.文件夹处理

# 递归的去拷贝文件夹
# 目标目录不能存在,注意对folder2目录父级目录要有可写权限,ignore的意思是排除
shutil.copytree('folder1', 'folder2', ignore=shutil.ignore_patterns('*.pyc', 'tmp*'))
# 拷贝软连接-通常的拷贝都把软连接拷贝成硬链接,即对待软连接来说是创建新的文件
shutil.copytree('f1', 'f2', symlinks=True, ignore=shutil.ignore_patterns('*.pyc', 'tmp*'))

# 递归的去删除文件
shutil.rmtree('要清空的文件夹名')

# 把一个文件从一个文件夹移动到另一个文件夹,并同时重命名
shutil.move('原文件夹/原文件名', '目标文件夹/目标文件名')

    4.压缩包处理

# 创建压缩包并返回文件的路径
shutil.make_archive(base_name, format,...)
"""参数说明
    base_name: 压缩包的文件名,也可以是压缩包的路径,只是文件名时,则保存至当前目录,否则保存至指定路径
        如: data_bak                       =>保存至当前路径
        如: /tmp/data_bak                  =>保存至/tmp/
    format: 压缩包种类,"zip", "tar", "bztar", "gztar"
    root_dir: 要压缩的文件夹路径(默认当前目录)
    owner: 用户,默认当前用户
    group: 组,默认当前组
    logger: 用于记录日志,通常是logging.Logger对象
"""

# 将 /data 下的文件打包放置当前程序目录
ret = shutil.make_archive("data_bak", 'gztar', root_dir='/data')

# 将 /data下的文件打包放置 /tmp/目录
ret = shutil.make_archive("/tmp/data_bak", 'gztar', root_dir='/data')

    5.压缩原理: shutil 对压缩包的处理是调用 ZipFile 和 TarFile 两个模块来进行的

        ZipFile压缩和解压缩

import zipfile

# 压缩
z = zipfile.ZipFile('laxi.zip', 'w')
z.write('a.log')
z.write('data.data')
z.close()

# 解压
z = zipfile.ZipFile('laxi.zip', 'r')
z.extractall(path='.')
z.close()

        TarFile压缩和解压缩

import tarfile

# 压缩
t=tarfile.open('/tmp/egon.tar', 'w')
t.add('/test1/a.py', arcname='a.bak')
t.add('/test1/b.py', arcname='b.bak')
t.close()

# 解压
t=tarfile.open('/tmp/egon.tar', 'r')
t.extractall('/egon')
t.close()

16.数学模块 math

import math

# 变量
math.e              自然对数的底e
math.pi             圆周率pi

# 函数
math.ceil(x)        对x向上取整,比如x=1.2,返回2
math.floor(x)       对x向下取整,比如x=1.2,返回1
math.sqrt(x)        返回x的平方根
math.factorial(x)   求x的阶乘
math.log(x[, base]) 返回以base为底x的对数, 如果不给出base,则以自然对数e为底
math.log10(x)       求以10为底x的对数
math.pow(x, y)      返回 x**y (x的y次方)
math.fabs(x)        返回浮点数x的绝对值

# 角度和弧度degrees互换
math.degree(x)      将弧度x转换为角度
math.radians(x)     将角度x转换为弧度

# 三角函数
math.sin(x)     返回x的正弦(x为弧度)
math.cos(x)     返回x的余弦(x为弧度)
math.tan(x)     返回x的正切(x为弧度)
math.asin(x)    返回x的反正弦(返回值为为弧度)
math.acos(x)    返回x的反余弦(返回值为为弧度)
math.atan(x)    返回x的反正切(返回值为为弧度)
posted @ 2020-08-15 23:23  唐雪成  阅读(644)  评论(0编辑  收藏  举报