装饰器,包与模块,常用库


一.装饰器

  • 在编程中有两个原则是要遵守的,也就是开放和封闭的原则
  1. 开发:对现有功能的拓展开放
  2. 封闭:已实现的功能代码不应该被修改
  • 如果我们的代码中有N个函数,我们需要在这N个函数中增加或者减少一个功能,那么就意味我们需要把相同的代码增加多次或者减少多次,这样就很不符合编程开放跟封闭的原则,而且也不是一个好的编程风格,解决这样问题的思路就是装饰器
  • 有一个登录,查看数据,查看钱包的代码如下:
    dict1={"isLogon":False}
    def logon():
        '''登录'''
        username=input("输入账号:\n")
        password=input("输入密码:\n")
        if username=="tang" and password=="123":
            dict1["isLogon"]=True
            print("登录成功")
        else:
            print("登录失败")
    def order():
        '''查看数据'''
        if dict1["isLogon"]:
            print("已授权查看后台数据")
        else:
            print("请先登录")
    def admin():
        '''查看钱包'''
        if dict1["isLogon"]:
            print("已授权查看钱包")
        else:
            print("请先登录")
    
    while True:
        a=int(input("1.登录 2.查看数据 3.查看钱包 4.退出\n"))
        if a==1:
            logon()
        elif a==2:
            order()
        elif a==3:
            admin()
        elif a==4:
            break

     按照现在的代码,如果我们需要更改登录代码的判断,·那我们后面查看数据跟查看钱包的代码都要更改,我们现在需要装饰器解决这个问题

    dict1={"isLogon":False}   #标识
    
    def outer(func):
        def inner():    #内部函数
            if dict1["isLogon"]:    #这里的函数就相当于if dict1["isLogon"]==True
                return func()
            else:
                print("请先登录")
        return inner   #返回执行函数inner
    
    def logon():
        '''登录'''
        username=input("输入账号:\n")
        password=input("输入密码:\n")
        if username=="tang" and password=="123":
            dict1["isLogon"]=True   #满足如果条件的话,会把字典dict1的value值改为True
            print("登录成功")
        else:
            print("登录失败")
    
    @outer
    def order():
        '''查看数据'''
        print("已授权查看后台数据")
    @outer
    def admin():
        '''查看钱包'''
        print("已授权查看钱包")
    
    while True:
        a=int(input("1.登录 2.查看数据 3.查看钱包 4.退出\n"))
        if   a==1:
            logon()
        elif a==2:
            order()
        elif a==3:
            admin()
        elif a==4:
            break
    • 执行的顺序为:
    1. 执行outer函数
    2. 执行内部函数inner
    3. 执行inner函数的返回值
    4. 执行inner函数里面的表达式
    • ?旦结合装饰器后,调?fun其实执?的是inner函数内部,原来的fun被覆盖
    • ?旦这个函数被装饰器装饰之后,被装饰的函数重新赋值成装饰器的内层函数

二.包package与模块module

已知现有一个包test,里面有两个模块(login.py跟logout.py)

def func():
    print("世界你好")

list1=["hello world"]
logout
  • 在同一个包下,一个模块login.py怎么引用另一个模块的代码logout.py

  1. import导入 具体为:import导入package包.module模块
    import test.logout   #先导入另外一个模块
    '''调用其他模块里面的函数'''
    test.logout.func()
    '''调用其他模块里面的变量'''
    print(test.logout.list1)

     输出:

    世界你好
    ['hello world']
  2. from package包.module模块 import *(所有)函数/变量/类
    from test.logout import *
    func()
    print(list1)

     输出:

    世界你好
    ['hello world']
  • 不同包之间的不同模块调用

    from package包.module模块 import *(所有)函数/变量/类
  • 包和包嵌套之间的调用

    from package包.package包.module模块 import *(所有)函数/变量/类

三.常用库

  • 标准库:安装了python的解释器,解释器内部自带的

1.os库/模块(operation system,操作系统)用于实现访问操作系统等相关的功能

      • 获取当前库所在本地磁盘路径
        import os   #导入库
        print(os.path.dirname(__file__))

         输出:

        F:\python\code\testdev\函数\常用库
      • 获取当前库所在本地磁盘路径的上一级目录
        import os   #导入库
        print(os.path.dirname(os.path.dirname(__file__)))

         输出:

        F:\python\code\testdev\函数
      • 输入控制台的命令(如查看IP地址)
        import os   #导入库
        print(os.system("ipconfig"))
      • 获取本地磁盘目录下所有的文件
        import os   #导入库
        for item in os.listdir("C:/"):
            print(item)
      • 获取当前的操作系统
        import os   #导入库
        print(os.name)
      • 路径的拼接——>自动获取路径——>读取文件
        import os
        
        base_dir=os.path.dirname(os.path.dirname(os.path.dirname(__file__)))   #获取文件所在的目录并定义为变量
        userPath=os.path.join(base_dir,"test","user.txt")
        f=open(userPath,"r",encoding="utf-8")
        print(f.read())
        f.close()

2.time库(time库能够表达计算机时间,提供获取系统时间并格式化输出的方法,提供系统级精确计时功能(可以用于程序性能分析)。)

   

格式化字符串 日期/时间说明 取值范围
%Y 年份 0000~9999
%m 月份(数字) 01~12
%B 月份(英文全称) January~December
%b 月份(英文缩写) Jan~Dec
%d 日期 01~31
%A 星期(英文全称) Monday~Sunday
%a 星期(英文缩写) Mon~Sun
%H 小时(24小时制) 00~23
%I 小时(12小时制) 01~12
%p 上/下午 AM,PM
%M 分钟 00~59
%S 00~59
      • 时间戳:
        JavaScript时间戳:是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总毫秒数

        Unix时间戳:是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数
      • 获取当前时间戳:
        import time as t  #导入time库别名为t
        
        print("获取当前时间戳:",t.time())

        输出:

        获取当前时间戳: 1637913653.626496
      • 获取当前时间的字符串格式
        import time as t  #导入time库别名为t
        
        print("获取当前时间的字符串格式:",t.ctime())

        输出:

        获取当前时间的字符串格式: Fri Nov 26 16:01:22 2021
      • 时间戳转为字符串
        import time as t  #导入time库别名为t
        
        print("时间戳转为字符串:",t.ctime(t.time())))

        输出:

        时间戳转为字符串: Fri Nov 26 16:02:12 2021
      • 时间戳转为struct_time
        import time as t  #导入time库别名为t
        
        print("时间戳转为struct_time:",t.gmtime(t.time()).tm_year)

        输出:

        时间戳转为struct_time: 2021
      • 时间戳转为本地时间
        import time as t  #导入time库别名为t
        
        print("时间戳转为本地时间:",t.localtime(t.time()))

        输出:

        时间戳转为本地时间: time.struct_time(tm_year=2021, tm_mon=11, tm_mday=26, tm_hour=16, tm_min=5, tm_sec=51, tm_wday=4, tm_yday=330, tm_isdst=0)
      • 获取中国时间
        import time as t  #导入time库别名为t
        
        print("获取中国时间:",t.strftime("%y-%m-%d %H:%M:%S",t.localtime()))

        输出:

        获取中国时间: 21-11-26 16:11:11

3.datetime库(相比较time的模块,datetime也是表示时间的,但是会更加直观)

      • 获取当前时间
        import datetime
        
        print("获取当前时间:",datetime.datetime.now())

        输出:

        获取当前时间: 2021-11-26 16:19:02.385842
      • 时间戳转换格式
        import datetime
        import  time
        print("时间戳转换格式:",datetime.datetime.fromtimestamp(time.time()))

        输出:

        时间戳转换格式: 2021-11-26 16:20:07.197038
      • 在当前时间增加或减少
        import datetime
        
        print("在当前时间增加8小时:",datetime.datetime.now()+datetime.timedelta(hours=8))
        print("在当前时间减少2小时:",datetime.datetime.now()+datetime.timedelta(hours=-2))

        输出:

        在当前时间增加8小时: 2021-11-27 00:21:38.241342
        在当前时间减少2小时: 2021-11-26 14:21:38.241342

4.json库

      • 序列化和反序列化:
        序列化:把内存里的数据类型转为字符串的数据类型,使能够存储到硬盘或通过网络传输到远程,因为硬盘或 者网络传输时只接受bytes的数据类型。简单的说就是把Python的数据类型(字典,元组,列表)转为str的数据类型过程
        反序列化,就是str的数据类型转为Python对象的过程。
      • 函数
        针对python对象 dumps() 对Python对象(list,tuple,dict)进行序列化
        loads() 对Python对象(list,tuple,dict)进行反序列化
        针对python文件 dump() 对文件进行序列化(本质上把内容写到文件里面)
        load() 对文件进行反序列化(本质上是读取文件里面的内容)
      • 列表的序列化和反序列化
        import json
        list1=["hello","world",1,2]
        #序列化
        listStr=json.dumps(list1)
        print(listStr)
        print(type(listStr))

        #反序列化
        strList=json.loads(listStr)
        print(strList)
        print(type(strList))

        输出:

        ["hello", "world", 1, 2]
        <class 'str'>
        ['hello', 'world', 1, 2]
        <class 'list'>
      • 元组的序列化和反序列化(元组反序列化之后会变成列表的数据类型
        import json
        tuple=("C","Python","Java")
        #元组的序列化
        tupleStr=json.dumps(tuple)
        print(tupleStr)
        print(type(tupleStr))

        #元组的反序列化(元组反序列化之后会变成列表的数据类型)
        strTuple=json.loads(tupleStr)
        print(strTuple)
        print(type(strTuple))

         输出:

        ["C", "Python", "Java"]
        <class 'str'>
        ['C', 'Python', 'Java']
        <class 'list'>
      • 字典的序列化和反序列化
        import json
        dict1={"name":"tang","city":"xian"}
        #序列化
        dictStr=json.dumps(dict1)
        print(dictStr)
        print(type(dictStr))

        #反序列化
        strDict=json.loads(dictStr)
        print(strDict)
        print(type(strDict))

        输出:

        {"name": "tang", "city": "xian"}
        <class 'str'>
        {'name': 'tang', 'city': 'xian'}
        <class 'dict'>

        字典在序列化如果有汉字时如果dict包含有汉字,一定加上ensure_ascii=False。否则按参数默认值True,意思是保证dumps之后的结果里所有的字符都能够被ascii表示,汉字在ascii的字符集里面,因此经过dumps以后的str里,汉字会变成对应的unicode

      • 文件的序列化和反序列化
        import json
        dict1= {"name": "tang", "city": "西安"}
        #序列化
        json.dump(dict1,open("index.txt","w"))

        #反序列化
        print(json.load(open("index.txt","r")))
        print(type(json.load(open("index.txt","r"))))

        输出:

        {'name': 'tang', 'city': '西安'}
        <class 'dict'>
      • 文件的序列化和反序列化本质上跟文件的读取没有区别

现在有一个结合文件读取的注册登录代码如下:

 1 def out():
 2     username = input("输入账号:\n")
 3     password = input("输入密码:\n")
 4     return username,password
 5 def register():
 6     '''注册'''
 7     username,password=out()
 8     temp=username+"|"+password
 9     temp=username+"|"+password
10     f=open("user.txt","w")
11     f.write(temp)
12     f.close()
13     print("注册成功")
14 def login():
15     '''登录'''
16     username,password=out()
17     f=open("user.txt","r")
18     list1=f.read().split("|")
19     f.close()
20     if username==list1[0] and password==list1[1]:
21         print("登录成功")
22     else:
23         print("账号密码错误")
24 if __name__ == '__main__':
25     while True:
26         a = int(input("1.注册 2.登录 3.退出\n"))
27         if a == 1:
28             register()
29         elif a == 2:
30             login()
31         elif a == 3:
32             break
注册登录

同样我们可以使用文件的序列化跟反序列化来完成:

import json
def out():
    username = input("输入账号:\n")
    password = input("输入密码:\n")
    return username,password
def register():
    '''注册'''
    username,password=out()
    temp=username+"|"+password
    json.dump(temp,open("user.txt","w"))
    print("注册成功")

def login():
    '''登录'''
    username,password=out()

    list1=str(json.load(open("user.txt","r"))).split("|")
    print(type(list1))
    if username==list1[0] and password==list1[1]:
        print("登录成功")
    else:
        print("账号密码错误")
if __name__ == '__main__':
    while True:
        a = int(input("1.注册 2.登录 3.退出\n"))
        if a == 1:
            register()
        elif a == 2:
            login()
        elif a == 3:
            break

5.sys库

      • 定义:

Python的sys模块提供访问由解释器使用或维护的变量的接口,并提供了一些函数用来和解释器进行交互,操控Python的运行时环境。

      • 查看python解释器版本
        import sys
        print(sys.version)

         输出结果:

        3.9.5 (tags/v3.9.5:0a7dcbd, May  3 2021, 17:27:52) [MSC v.1928 64 bit (AMD64)]
      • 查看解释器所在本地路径
        import sys
        for item in sys.path:
             print(item)

         输出结果:

        F:\python\code\testshare\练习\share
        F:\python\code\testshare
        F:\Python3\python39.zip
        F:\Python3\DLLs
        F:\Python3\lib
        F:\Python3
        F:\Python3\lib\site-packages
      • 查看操作系统
        import sys
        print(sys.platform)

        输出结果:

        win32
      • 搜索模块的路径集
        import sys
        print(sys.path)

        输出结果:

        ['F:\\python\\code\\testshare\\练习\\share', 'F:\\python\\code\\testshare', 'F:\\Python3\\python39.zip', 'F:\\Python3\\DLLs', 'F:\\Python3\\lib', 'F:\\Python3', 'F:\\Python3\\lib\\site-packages']
      • 在工作或者写代码的阶段,当导入的方式是正确的,但是提示模块不存在,那么这个时候我们使用sys来解决(把不存在模块的路径加到sys执行的路径中)
        import os
        import sys   #导入库
        base_dir=os.path.dirname(os.path.dirname(__file__))   #查看文件上一级路径
        day12Path=os.path.join(base_dir,"day12")   #拼接路径
        sys.path.append(day12Path)   #添加到路径到sys.path中
        from login import * #导入模块
        func()   #调用函数

6.hashlib库(md5的加密算法)

      • open api :开发平台的接口
      • open api的加密思路:
        1. 对请求参数进行排序,根据key来进行排序
        2. 把请求参数处理成key=value&key=value
        3. 对请求参数进行md5的加密(加密的数据类型必须是bytes的数据类型)
        4. 把加密后的sign当作请求头给服务端发送过去,服务层进行比较,如果一致,可以请求,如果不一致,拒绝请求
      • 实战
        import hashlib
        import time
        from urllib import parse
        def sign():     #定义函数
            dict1={"name":"tang","age":21,"city":"xian","time":time.time()}
            #在字典中添加时间戳(因为时间戳是一直改变的,所以加密之后也是不一样的)
            data=dict(sorted(dict1.items(),key=lambda item:item[0]))
            #对字典的key值进行排序
            data=parse.urlencode(data)
            #把请求参数处理成key=value&key=value
            m=hashlib.md5()
            #获取md5的对象
            m.update(data.encode("utf-8"))
            #把str转为bytes的数据类型,进行具体的加密
            return m.hexdigest()
        
        print(sign())
    • 输出结果:
      f6e9e06c2ef9b47f81d24b83da1b4448
  • 第三方库:由很多的顶级程序员开发的,需要额外安装

    • 安装:pip3 install 第三方库的名称

安装方式:打开控制台输入pip3 install 第三方库的名称即可

C:\Users\特昂糖>pip3 install flask
Collecting flask
  Downloading Flask-2.0.2-py3-none-any.whl (95 kB)
     |████████████████████████████████| 95 kB 306 kB/s
Collecting Werkzeug>=2.0
  Downloading Werkzeug-2.0.2-py3-none-any.whl (288 kB)
     |████████████████████████████████| 288 kB 1.7 MB/s
Collecting Jinja2>=3.0
  Downloading Jinja2-3.0.3-py3-none-any.whl (133 kB)
     |████████████████████████████████| 133 kB 3.3 MB/s
Collecting itsdangerous>=2.0
  Downloading itsdangerous-2.0.1-py3-none-any.whl (18 kB)
Collecting click>=7.1.2
  Downloading click-8.0.3-py3-none-any.whl (97 kB)
     |████████████████████████████████| 97 kB 1.4 MB/s
Requirement already satisfied: colorama in f:\python3\lib\site-packages (from click>=7.1.2->flask) (0.4.4)
Collecting MarkupSafe>=2.0
  Downloading MarkupSafe-2.0.1-cp39-cp39-win_amd64.whl (14 kB)
Installing collected packages: MarkupSafe, Werkzeug, Jinja2, itsdangerous, click, flask
Successfully installed Jinja2-3.0.3 MarkupSafe-2.0.1 Werkzeug-2.0.2 click-8.0.3 flask-2.0.2 itsdangerous-2.0.1
WARNING: You are using pip version 21.1.1; however, version 21.3.1 is available.
You should consider upgrading via the 'f:\python3\python.exe -m pip install --upgrade pip' command.
安装第三方库
    • 卸载:pip3 uninstall 第三方库的名称

    • 常用的第三方库:

              pip3 install pytest(单元测试框架)
              pip3 install flask(轻量级web框架)
              pip3 install django(全栈web框架)
              pip3 install requests(做接口测试的库,也可以做网络爬虫)
              pip3 install pymysql(操作MySQL数据库)
              pip3 install xlrd(操作Excel)
              pip3 install selenium(做UI自动化测试)