1. 内容大纲

    1. 自定义模块
    2. 模块是什么?
    3. 为什么要有模块?
      • 什么是脚本?
    4. 模块的分类
    5. import的使用
      • 第一次导入模块执行三件事
      • 被导入模块有独立的名称空间
      • 为模块起别名
      • 导入多个模块
    6. from ... import ...
      • from ... import ...的使用
      • from ... import ... 与import对比
      • 一行导入多个
      • from ... import *
      • 模块循环导入的问题
      • py文件的两种功能
      • 模块的搜索路径
    7. json pickle 模块
    8. hashlib模块
  2. 具体内容

    1. 自定义模块:自定义模块名不能与内置模块名重名。

    2. 模块是什么?

      将20万行代码全部放在一个py文件中?为什么不行?

      1. 代码太多,读取代码耗时太长.
        2. 代码不容易维护.

      将相同的功能封装到一个文件中,这个存储着很多常用的功能的py文件,就是模块。 模块就是文件,存放一堆常用的函数,谁用谁拿。一个函数就是一个功能,把一些常用的函数放在一个py文件中,这个文件就称之为模块。模块就是一些常用功能的集合体。

      模块就是一个py文件,是常用的相似功能的集合.

    3. 为什么要使用模块?

      • 拿来主义,提高开发效率.
      • 便于管理维护.

      • 什么是脚本?
        • 脚本就是py文件,长期保存代码的文件.
    4. 模块的分类

      1. 内置模块,也叫做标准库。此类模块就是python解释器给你提供的,比如我们之前见过的time模块,os模块。标准库的模块非常多(200多个,每个模块又有很多功能)

      2. 第三方模块,第三方库。一些python大神写的非常好用的模块,必须通过pip install 指令安装的模块,比如BeautfulSoup, Django,等等。大概有6000多个。

      3. 自定义模块,我们自己在项目中定义的一些模块。自己写的一个py文件。定义一个模块其实很简单就是写一个文件,里面写一些代码(变量,函数)即可

        # xxx.py  (自定义模块)
        
        #print('from the xxx.py')
        name = '太白金星'
        
        def read1():
            print('xxx模块:',name)
        
        def read2():
            print('xxx模块')
            read1()
        
        def change():
            global name
            name = 'barry'
            print(name)
    5. import的使用: 注意:引用模块写在最上面,不要写在函数里。

      import 模块 先要怎么样?

      import xxx 执行一次xxx这个模块里面的所有代码

      ​ 模块可以包含可执行的语句和函数的定义,这些语句的目的是初始化模块,它们只在模块名第一次遇到导入import语句时才执行。

      ​ import语句是可以在程序中的任意位置使用的,且针对同一个模块import多次,为了防止你重复导入,python的优化手段是:第一次引用某个模块,会将这个模块里面的所有代码加载到内存,只要你的程序没有结束,接下来你在引用多少次,它会先从内存中寻找有没有此模块,如果已经加载到内存,就不在重复加载。后续的import语句仅是对已经加载到内存中的模块对象增加了一次引用,不会重新执行模块内的语句。

      • 第一次导入模块执行三件事 ***

          1. 在内存中创建一个以被导入模块名命名的名称空间.(一个py文件有一个名称空间

          2. 执行此名称空间所有的可执行代码(将xxx.py文件中所有的变量与值的对应关系加载到这个名称空间).

          3. 通过 模块名. 的方式引用模块里面的内容(变量,函数名,类名等)。 ps:重复导入会直接引用内存中已经加载好的结果

            import xxx
            print(xxx.name)
            xxx.read1()
            

      • 被导入模块有独立的名称空间 ***

        被导入模块有独立的名称空间,它只能操作自己空间中的所有内容,不能操作导入该模块的py文件中的内容。每个模块都是一个独立的全局名称空间,用来定义这个模块中的函数,把这个模块的名称空间当做全局名称空间,这样我们在编写自己的模块时,就不用担心我们定义在自己模块中全局变量在被导入时,会与使用者的全局变量冲突。
         #
         import xxx
         name = 'alex'
         print(name)
         print(xxx.name)
         #结果:
          alex
          太白金星
        
         #
         import xxx
         def read1():
             print(666)
         xxx.read1()
        #结果:
        xxx模块: 太白金星
        
         #
         import xxx
         name = '日天'
         xxx.change()  #barry
         print(name)  # 日天
         print(xxx.name)  # barry

      • 为模块起别名 **

        • 1 简单,便捷,将长的模块名改为短的模块名

           import xxx as m
           print(m.name)
          #结果:
          太白金星
          
        • 2,有利于代码的简化.

          # 原始写法:
           result = input('请输入')
           if result == 'mysql':
               import mysql1
               mysql1.mysql()
           elif result == 'oracle':
               import oracle1
               oracle1.oracle()
          
          # 起别名:
           result = input('请输入')
           if result == 'mysql':
               import mysql1 as m
           elif result == 'oracle':
               import oracle1 as m
             ''' 后面还有很多'''
           m.db()  # 统一接口,归一化思想
      • 导入多个模块:多行导入,易于阅读 ,易于编辑 ,易于搜索 ,易于维护。

        import time, os, sys  # 这样写不好
        # 应该向以下这种写法:
        import time
        import os
        import sys
    6. from ... import ...

      • from ... import ...的使用

         from xxx import name
         from xxx import read1
         from xxx import read2
         print(name)#太白金星
         print(globals())
         read1()#xxx模块: 太白金星
      • from ... import ... 与import对比 ***

        1. from.. import 用起来更方便,在当前名称空间中,直接使用名字就可以了,无需加前缀:xxx.

          from xxx import name
          print(name)
        2. from...import 容易与当前执行文件中的名字产生冲突.

          # 容易产生冲突,后者将前者覆盖。执行文件有与模块同名的变量或者函数名,会有覆盖效果
           name = 'alex'
           from xxx import name
           print(name)#太白金星
          
          
        3. 当前位置直接使用read1和read2,执行时,仍然以xxx.py文件全局名称空间 ***

          #
          from xxx import read1
          def read1():
              print(666)
          read1()#666 
          
          #
          from xxx import read1
          name = '大壮'
          read1()#xxx模块: 太白金星
          print(globals())
          
          #
          from xxx import change
          name = 'Alex'
          print(name)  # 'Alex'
          change()  # 'barry'
          from xxx import name
          print(name)#barry
          
          
          
      • 一行导入多个

        from tbjx import name,read1,read2  # 这样不好
        from tbjx import name
        from tbjx import read1
        
      • from ... import *

        • 把xxx.py中所有的不是以下划线(_)开头的名字都导入到当前位置,大部分情况下我们的python程序不应该使用这种导入方式,因为*你不知道你导入什么名字,很有可能会覆盖掉你之前已经定义的名字。而且可读性极其的差。一般千万别么这写,必须要将这个模块中的所有名字全部记住.但是可以配合一个变量使用

           #  xxx.py
            __all__ = ['name', 'read1']  # 配合*使用    注:没写到__all__中的变量,可以单独引用
          
            name = '太白金星'
          
           def read1():
               print('tbjx模块:', name)
          
           def read2():
               print('tbjx模块')
               read1()
           def change():
               global name
               name = 'barry'
               print(name)
          
      • 模块循环导入的问题:模块循环/嵌套导入抛出异常的根本原因是由于在python中模块被导入一次之后,就不会重新导入,只会在第一次导入时执行模块内代码。在我们的项目中应该尽量避免出现循环/嵌套导入,如果出现多个模块都需要共享的数据,可以将共享的数据集中存放到某一个地方。当程序出现了循环/嵌套导入后的异常分析、解决方法如下(了解,以后尽量避免

            #创建一个m1.py
                print('正在导入m1') 
                from m2 import y
                x='m1'
        
            #创建一个m2.py
                print('正在导入m2')
                from m1 import x
                y='m2'
        
            #创建一个run.py
                import m1
        
            #测试一
            执行run.py会抛出异常
            正在导入m1
            正在导入m2
            Traceback (most recent call last):
              File "/Users/linhaifeng/PycharmProjects/pro01/1 aaaa练习目录/aa.py", line 1, in <module>
                import m1
              File "/Users/linhaifeng/PycharmProjects/pro01/1 aaaa练习目录/m1.py", line 2, in <module>
                from m2 import y
              File "/Users/linhaifeng/PycharmProjects/pro01/1 aaaa练习目录/m2.py", line 2, in <module>
                from m1 import x
            ImportError: cannot import name 'x'
        
        
            #测试一结果分析
            先执行run.py--->执行import m1,开始导入m1并运行其内部代码--->打印内容"正在导入m1"--->执行from m2 import y 开始导入m2并运行其内部代码--->打印内容“正在导入m2”--->执行from m1 import x,由于m1已经被导入过了,所以不会重新导入,所以直接去m1中拿x,然而x此时并没有存在于m1中,所以报错
        
        
            #测试二:执行文件不等于导入文件,比如执行m1.py不等于导入了m1
            直接执行m1.py抛出异常
            正在导入m1
            正在导入m2
            正在导入m1
            Traceback (most recent call last):
              File "/Users/linhaifeng/PycharmProjects/pro01/1 aaaa练习目录/m1.py", line 2, in <module>
                from m2 import y
              File "/Users/linhaifeng/PycharmProjects/pro01/1 aaaa练习目录/m2.py", line 2, in <module>
                from m1 import x
              File "/Users/linhaifeng/PycharmProjects/pro01/1 aaaa练习目录/m1.py", line 2, in <module>
                from m2 import y
            ImportError: cannot import name 'y'
        
        
            #测试二分析
            执行m1.py,打印“正在导入m1”,执行from m2 import y ,导入m2进而执行m2.py内部代码--->打印"正在导入m2",执行from m1 import x,此时m1是第一次被导入,执行m1.py并不等于导入了m1,于是开始导入m1并执行其内部代码--->打印"正在导入m1",执行from m1 import y,由于m1已经被导入过了,所以无需继续导入而直接问m2要y,然而y此时并没有存在于m2中所以报
        
        
        # 解决方法:
            方法一:导入语句放到最后
            #m1.py
                print('正在导入m1')
                x='m1'
                from m2 import y
        
            #m2.py
                print('正在导入m2')
                y='m2'
                from m1 import x
        
            方法二:导入语句放到函数中
            #m1.py
                print('正在导入m1')
                def f1():
                    from m2 import y
                    print(x,y)
                x = 'm1'
                # f1()
        
            #m2.py
                print('正在导入m2')
                def f2():
                    from m1 import x
                    print(x,y
                y = 'm2'
        
            #run.py
                import m1
                m1.f1()
        
      • py文件的两种功能:

        1. 自己使用, 当做脚本,一个文件就是整个程序,用来被执行

        2. 被别人引用 ,当做模块使用,文件中存放着一堆功能,用来被导入使用

          python为我们内置了全局变量__name__  
          
          #用来控制.py文件在不同的应用场景下执行不同的逻辑
            print(__name__)
            当tbjx.py做脚本: __name__ == __main__  返回True
            当tbjx.py做模块被别人引用时: __name__ == xxx(模块名)
          
           # __name__ 根据文件的扮演的角色(脚本,模块)不同而得到不同的结果
          
          1, 模块需要调试时,加上 if __name__ == '__main__':
          
            change()  # 测试代码
            if __name__ == '__main__':
                change()
          
           2, 作为项目的启动文件需要用.
          
          
      • 模块的搜索路径 ***
    
            #import abc  abc也是一个内置模块
            # python 解释器会自动将一些内置内容(内置函数,内置模块等等)加载到内存中

            import sys
            print(sys.modules)  # 内置内容(内置函数,内置模块等等)
            print(sys.path)
            #['D:\python_22\day17', 'C:\Python\Python36\python36.zip', 'C:\Python\Python36\DLLs', 'C:\Python\Python36\lib', 'C:\Python\Python36', 'C:\Python\Python36\lib\site-packages']

            # 'D:\python_22\day17' 路径是当前执行文件的相对路径

            #要想导入dz.py模块: 内存中没有,内置模块也没有,这两个你左右不了,但是sys.path你可以操作.
            import sys
            sys.path.append(r'D:python_22day16')  # sys.path 会自动将你的 当前目录的路径加载到列表中.  D:python_22day16 是dz.py的相对路径
            import dz
    
    # 如果你想要引用你自定义的模块:
     要不你就将这个模块放到当前目录下面,要不你就手动添加到sys.path
    
        模块的查找顺序:
    
          Python中引用模块是按照一定的规则以及顺序去寻找的,这个查询顺序为:先从内存中已经加载的模块进行寻找,找不到再从内置模块中寻找,内置模块如果也没有,最后去sys.path中路径包含的模块中寻找。它只会按照这个顺序从这些指定的地方去寻找,如果最终都没有找到,那么就会报错。

    注意的是:我们自定义的模块名不应该与系统内置模块重名

  1. json pickle 模块

    序列化模块: 将一种数据结构(list,tuple,dict ....)转化成特殊的序列.

    为什么存在序列化?

    数据 ----> bytes

    只有字符串类型和bytes可以互换.

    dict,list..... -------> str <--------> bytes

    数据存储在文件中,str(bytes类型)形式存储,比如字典.

    数据通过网络传输(bytes类型),str 不能还原回去.

特殊的字符串:序列化.

序列化模块:

json模块 : (重点

  1. 不同语言都遵循的一种数据转化格式,即不同语言都使用的特殊字符串。(比如Python的一个列表[1, 2, 3]利用json转化成特殊的字符串,然后在编码成bytes发送给php的开发者,php的开发者就可以解码成特殊的字符串,然后在反解成原数组(列表): [1, 2, 3])

  2. json序列化只支持部分Python数据结构:dict,list, tuple,str,int, float,True,False,None

            
         dumps loads 主要用于网络传输,但是也可以读写文件,但一般用dump,load读写文件
               
                 import json
                 dic = {'username': '太白', 'password': 123,'status': True}
                 # 转化成特殊的字符串
                 st = json.dumps(dic)
                 print(st,type(st))#{"username": "u592au767d", "password": 123, "status": true} <class 'str'>
                 
                 st = json.dumps(dic,ensure_ascii=False)  #不使用ASCII,使用Unicode,可以显示中文
                 print(st,type(st))#{"username": "太白", "password": 123, "status": true} <class 'str'>

                 #反转回去
                 dic1 = json.loads(st)
                 print(dic1,type(dic1))#{'username': '太白', 'password': 123, 'status': True} <class 'dict'>

                 # 写入文件
                 l1 = [1, 2, 3, {'name': 'alex'}]
                # 转化成特殊的字符串写入文件
                 with open('json文件',encoding='utf-8',mode='w') as f1:
                     st = json.dumps(l1)  #先转化成特殊的字符串
                     f1.write(st)

                # 读取出来还原回去
                 with open('json文件',encoding='utf-8') as f2:
                     st = f2.read()
                     l1 = json.loads(st)
                     print(l1,type(l1))#[1, 2, 3, {'name': 'alex'}] <class 'list'>
            
            
            
            # 特殊的参数??????
            
            
            
            
            博客
            
            
            
            

         dump load 只能用于写入文件,只能写入一个数据结构
             import json
             l1 = [1, 2, 3, {'name': 'alex'}]
             with open('json文件1',encoding='utf-8',mode='w') as f1:
                 json.dump(l1,f1)

            # 读取数据
             with open('json文件1',encoding='utf-8') as f2:
                 l1 = json.load(f2)
                 print(l1,type(l1))#[1, 2, 3, {'name': 'alex'}] <class 'list'>


            # 一次写入文件多个数据怎么做?

            # 错误示例:
                 dic1 = {'username': 'alex'}
                 dic2 = {'username': '太白'}
                 dic3 = {'username': '大壮'}
                # 写入数据
                 with open('json文件1',encoding='utf-8',mode='w') as f1:
                     json.dump(dic1,f1)
                     json.dump(dic2,f1)
                     json.dump(dic3,f1)

                # 读取数据
                 with open('json文件1',encoding='utf-8') as f1:
                     print(json.load(f1))#报错
                     print(json.load(f1))#报错
                     print(json.load(f1))#报错


            # 正确写法:  用 dumps loads
             dic1 = {'username': 'alex'}
             dic2 = {'username': '太白'}
             dic3 = {'username': '大壮'}
             with open('json文件1',encoding='utf-8',mode='w') as f1:
                 f1.write(json.dumps(dic1) + 'n')
                 f1.write(json.dumps(dic2) + 'n')
                 f1.write(json.dumps(dic3) + 'n')

             with open('json文件1',encoding='utf-8') as f1:
                 for i in f1:
                     print(json.loads(i))
             #结果:
            {'username': 'alex'}
            {'username': '太白'}
            {'username': '大壮'}



​ pickle模块:

  1. 只能是Python语言遵循的一种数据转化格式,只能在python语言中使用。

  2. 支持Python所有的数据类型,包括实例化对象。

            l1 = [1, 2, 3, {'name': 'alex'}]

          dumps loads 只能用于网络传输,不能写入文件
             
             import pickle
             st = pickle.dumps(l1)
             print(st)  # bytes类型   b'x80x03]qx00(Kx01Kx02Kx03}qx01Xx04x00x00x00nameqx02Xx04x00x00x00alexqx03se.'
            
             l2 = pickle.loads(st)
             print(l2,type(l2))#[1, 2, 3, {'name': 'alex'}] <class 'list'>

          dump load 直接写入文件,可以一次写入多个数据
             import pickle
             dic1 = {'name':'oldboy1'}
             dic2 = {'name':'oldboy2'}
             dic3 = {'name':'oldboy3'}
            
             f = open('pick多数据',mode='wb')
             pickle.dump(dic1,f)
             pickle.dump(dic2,f)
             pickle.dump(dic3,f)
             f.close()
                
             import pickle
             f = open('pick多数据',mode='rb')
             print(pickle.load(f))
             print(pickle.load(f))
             print(pickle.load(f))
             f.close()
             #结果:
            {'name': 'oldboy1'}
            {'name': 'oldboy2'}
            {'name': 'oldboy3'}

            #或者:
            f = open('pick多数据',mode='rb')
            while True:
                try:
                    print(pickle.load(f))
                except EOFError:
                    break
            f.close()
            # {'name': 'oldboy1'}
            # {'name': 'oldboy2'}
            # {'name': 'oldboy3'}   

                
            #写入函数名
            import pickle
            def func():
                print('in func')

             f = open('pick对象',mode='wb')
             pickle.dump(func,f)  #注意参数顺序  函数名func,文件句柄
             f.close()

             f = open('pick对象', mode='rb')
             ret = pickle.load(f)
             print(ret)#<function func at 0x0000020F2F9C1E18>  内存地址
             ret()#in func
  1. hashlib模块

    包含很多的加密算法. MD5, sha1 sha256 sha512......

    用途:

    1. 密码加密.不能以明文的形式存储密码.密文的形式.
    2. 文件的校验.

    用法:

    1. 将bytes类型字节 转化成 固定长度的16进制数字组成的字符串.
    2. 不同的bytes利用相同的算法(MD5)转化成的结果一定不同.
    3. 相同的bytes利用相同的算法(MD5)转化成的结果一定相同.
    4. hashlib算法不可逆(MD5中国王晓云破解了).
           1.密码加密:
            # md5
             s1 = 'kfdslfjasdlfgjsdlgkhsdafkshdafjksdfsdkfhjsdafj老fhdskafhsdkjfdsa男孩教育'
             import hashlib
             ret = hashlib.md5()
             ret.update(s1.encode('utf-8'))
            print(ret.hexdigest(),type(ret.hexdigest())) # 18f127c24462dd59287798ea5c0c0c2f <class 'str'>

            # 相关练习
             import hashlib
             def MD5(pwd):
                 ret = hashlib.md5()
                 ret.update(pwd.encode('utf-8'))
                 return ret.hexdigest()
            
            
             def register():
                 username = input('请输入用户名:').strip()
                 password = input('请输入密码:').strip()
                 password_md5 = MD5(password)
                 with open('register',encoding='utf-8',mode='a') as f1:
                     f1.write(f'n{username}|{password_md5}')
            
             register()
            
             def login():
                 username = input('请输入用户名:').strip()
                 password = input('请输入密码:').strip()
                 password_md5 = MD5(password)
            
                        ??????
            
            
            
            # 普通加密
             
             # 123456:  18f127c24462dd59258898ea5c0c0c2f
             # 000000:  18f127c24462dd59258898we5c0c0c2f

             s2 = '19890425'
             ret = hashlib.md5()
             ret.update(s2.encode('utf-8'))
             print(ret.hexdigest())  # 6e942d04cf7ceeeba09e3f2c7c03dc44
            
            普通的md5加密,非常简单,几行代码就可以了,但是这种加密级别是最低的,相对来说不很安全。虽然说hashlib加密是不可逆的加密方式,但也是可以破解的,那么他是如何做的呢?你看网上好多MD5解密软件,他们就是用最low的方式,空间换时间。他们会把常用的一些密码比如:123456,111111,以及他们的md5的值做成对应关系,类似于字典,dic = {'e10adc3949ba59abbe56e057f20f883e': 123456},然后通过你的密文获取对应的密码。只要空间足够大,那么里面容纳的密码会非常多,利用空间换取破解时间。 所以针对刚才说的情况,我们有更安全的加密方式:加盐。

            # 加盐

             s2 = '19890425'
             ret = hashlib.md5('太白金星'.encode('utf-8'))
             ret.update(s2.encode('utf-8'))
             print(ret.hexdigest())  # 84c31bbb6f6f494fb12beeb7de4777e1


            # 动态的盐
             s2 = '19890425'
             ret = hashlib.md5('太白金星'[::2].encode('utf-8'))   #比如用户名切片
             ret.update(s2.encode('utf-8'))
             print(ret.hexdigest())  # 84c31bbb6f6f494fb12beeb7de4777e1


            # sha系列  金融类,安全类.用这个级别.
             随着sha系列数字越高,加密越复杂,越不易破解,但是耗时越长.
            
             s2 = '198fdsl;fdsklgfjsdlgdsjlfkjsdalfksjdal90425'
             ret = hashlib.sha3_512()
             ret.update(s2.encode('utf-8'))
             print(ret.hexdigest())  # 4d623c6701995c989f400f7e7eef0c4fd4ff15194751f5cb7fb812c7d42a7406ca0349ea3447d245ca29b48a941e2f2f66579fb090babb73eb2b446391a8e102



            2.文件的校验
            

             linux中一切皆文件: 文本文件,非文本文件,音频,视频,图片...  
             无论你下载的视频,还是软件(国外的软件),往往都会有一个md5值,下载完后先测试md5值,然后其与提供的md5值对比,完全一致,则证明没问题

            #官网下载pycharm
            sha256 : 6217ce726fc8ccd48ec76e9f92d15feecd20422c30367c6dc8c222ab352a3ec6  *pycharm-professional-2019.1.2.exe
            
            #一次性全部update(类比文件)
             s1 = '我叫太白金星 今年18岁'
             ret = hashlib.sha256()
             ret.update(s1.encode('utf-8'))
             print(ret.hexdigest())  # 54fab159ad8f0bfc5df726a70332f111c2c54d31849fb1e4dc1fcc176e9e4cdc
            
            #分着update(类比文件)
             ret = hashlib.sha256()
             ret.update('我叫'.encode('utf-8'))
             ret.update('太白金星'.encode('utf-8'))
             ret.update(' 今年'.encode('utf-8'))
             ret.update('18岁'.encode('utf-8'))
             print(ret.hexdigest())  # 54fab159ad8f0bfc5df726a70332f111c2c54d31849fb1e4dc1fcc176e9e4cdc

            # low版校验:
            def file_md5(path):
                ret = hashlib.sha256()
                with open(path,mode='rb') as f1:  #以rb方式读取
                    b1 = f1.read()  #文件过大会撑爆内存
                    ret.update(b1)
                return ret.hexdigest()
            result = file_md5('pycharm-professional-2019.1.2.exe')
            print(result)  # 6217ce726fc8ccd48ec76e9f92d15feecd20422c30367c6dc8c222ab352a3ec6

            # 高大上版:
            def file_check(file_path):
            with open(file_path,mode='rb') as f1:
                sha256 = hashlib.sha256()
                while 1:
                    content = f1.read(1024)
                    if content:
                        sha256.update(content)
                    else:
                        return sha256.hexdigest()
            print(file_check('pycharm-professional-2019.1.1.exe'))

总结

  1. import 三件事, import的名字如果调用? 模块名.的方式调用.

  2. from ... import ... 容易产生冲突,独立的空间.

  3. __name__问题

  4. 模块的搜索路径

    内存 内置 sys.path

  5. 序列化模块:

    1. json最最常用(两对四个方法就行) 一定要掌握
    2. pickle(两对四个方法就行) 尽量掌握
  6. hashlib

    1. 密码的加密 ,文件的校验

内容来源于网络如有侵权请私信删除
你还没有登录,请先登录注册
  • 还没有人评论,欢迎说说您的想法!