VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > Python基础教程 >
  • python基础教程之模块(定义,分类,导入),j

  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文件中的内容。每个模块都是一个独立的全局名称空间,用来定义这个模块中的函数,把这个模块的名称空间当做全局名称空间,这样我们在编写自己的模块时,就不用担心我们定义在自己模块中全局变量在被导入时,会与使用者的全局变量冲突。
        从基本概念来说, 一个名称空间就是一个从名称到对象的关系映射集合。 我们已经明确地知道, 模块名称是它们的属性名称中的一个重要部分。 例如string 模块中的 atoi() 函数就是 string.atoi() 。给定一个模块名之后, 只可能有一个模块被导入到 Python 解释器中, 所以在不同模块间不会出现名称交叉现象; 所以每个模块都定义了它自己的唯一的名称空间。 如果我在我自己的模块 mymodule 里创建了一个 atoi() 函数, 那么它的名字应该是 mymodule.atoi() 。 所以即使属性之间有名称冲突, 但它们的完整授权名称(fullyqualified name)——通过句点属性标识指定了各自的名称空间 - 防止了名称冲突的发生。
         #
         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 xxx import change
           name = 'Alex'
           print(name)  # 'Alex'
           change()  # 'barry'
           print(name) # 'Alex'
          
          
      • 一行导入多个

        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_22\day16')  # sys.path 会自动将你的 当前目录的路径加载到列表中.  D:\python_22\day16 是dz.py的相对路径
            import dz
    
    # 如果你想要引用你自定义的模块:
     要不你就将这个模块放到当前目录下面,要不你就手动添加到sys.path
    
        模块的查找顺序:
    
          Python中引用模块是按照一定的规则以及顺序去寻找的,这个查询顺序为:先从内存中已经加载的模块进行寻找,找不到再从内置模块中寻找,内置模块如果也没有,最后去sys.path中路径包含的模块中寻找。它只会按照这个顺序从这些指定的地方去寻找,如果最终都没有找到,那么就会报错。

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

  1. json pickle 模块

    序列化模块: 将一种数据结构(list,tuple,dict ....)转化成特殊的序列。并且这个特殊的序列还可以反解回去。它的主要用途:文件读写数据,网络传输数据。json pickle shelve

    为什么存在序列化?

    数据 ----> bytes

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

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

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

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

特殊的字符串:将一种数据结构(如字典、列表)等转换成一个特殊的序列(字符串或者bytes)的过程就叫做序列化。如果你写入文件中的字符串是一个序列化后的特殊的字符串,那么当你从文件中读取出来,是可以转化回原数据结构的。

序列化模块:

​ 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

  3. json模块是将满足条件的数据结构转化成特殊的字符串,并且也可以反序列化还原回去。序列化模块总共只有两种用法,要不就是用于网络传输的中间环节,要不就是文件存储的中间环节,所以json模块总共就有两对四个方法:

    ​ 用于网络传输:dumps、loads

    ​ 用于文件写读:dump、load

            
         dumps loads 主要用于网络传输,但是也可以读写文件,但一般用dump,load读写文件
               
                 import json
                 dic = {'username': '太白', 'password': 123,'status': True}
                 # 转化成特殊的字符串
                 st = json.dumps(dic)
                 print(st,type(st))#{"username": "\u592a\u767d", "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'>
                 #注意,json转换完的字符串类型的字典中的字符串是由""表示的
                 
                 #反转回去
                 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'>
            
            
            
            # 特殊的参数:
            ensure_ascii:,当它为True的时候,所有非ASCII码字符显示为\uXXXX序列,只需在dump时将ensure_ascii设置为False即可,此时存入json的中文即可正常显示。 separators:分隔符,实际上是(item_separator, dict_separator)的一个元组,默认的就是(‘,’,’:’);这表示dictionary内keys之间用“,”隔开,而KEY和value之间用“:”隔开。 sort_keys:将数据根据keys的值进行排序。 剩下的自己看源码研究
            
            

         dump load 只能用于写入文件,只能写入一个数据结构
             import json
             l1 = [1, 2, 3, {'name': 'alex'}]
             with open('json文件1.json',encoding='utf-8',mode='w') as f1:  # json文件也是文件,就是专门存储json字符串的文件。
                 json.dump(l1,f1) # dump方法接收一个文件句柄,直接将l1转换成json字符串写入文件

            # 读取数据
             with open('json文件1.json',encoding='utf-8') as f2:
                 l1 = json.load(f2)# load方法接收一个文件句柄,直接将文件中的json字符串转换成数据结构返回
                 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所有的数据类型,包括实例化对象。pickle模块是将Python所有的数据结构以及对象等转化成bytes类型,然后还可以反序列化还原回去。

    • 用于网络传输:dumps、loads
    • 用于文件写读:dump、load

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

          dumps loads 只能用于网络传输,不能写入文件
             
             import pickle
             st = pickle.dumps(l1)
             print(st)  # bytes类型   b'\x80\x03]q\x00(K\x01K\x02K\x03}q\x01X\x04\x00\x00\x00nameq\x02X\x04\x00\x00\x00alexq\x03se.'
            
             l2 = pickle.loads(st)
             print(l2,type(l2))#[1, 2, 3, {'name': 'alex'}] <class 'list'>
            
            # 还可以序列化对象
            import pickle
            
            def func():
                print(666)

            ret = pickle.dumps(func)
            print(ret,type(ret))  # b'\x80\x03c__main__\nfunc\nq\x00.' <class 'bytes'>
            
            f1 = pickle.loads(ret)  # f1得到 func函数的内存地址
            f1()  # 执行func函数

          
        dump load 直接写入文件,可以一次写入多个数据
            
             #pickle序列化存储多个数据到一个文件中
             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模块

    摘要算法,也叫做加密算法,或者是哈希算法,散列算法等等,它通过一个函数,把任意长度的数据按照一定规则转换为一个固定长度的数据串(通常用16进制的字符串表示)。

    hashlib模块就相当于一个算法的集合,这里面包含着很多的加密算法. MD5, sha1 sha256 sha512......

    用途:

    1. 密码加密: 不能以明文的形式存储密码,一般我们存储密码时都要以密文的形式.比如:太黑|e10adc3949ba59abbe56e057f20f883e
    2. 文件的校验:文件一致性校验

    用法:

    1. 将bytes类型字节 ---> 通过hashlib算法 ---> 固定长度的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 get_user_pwd():  #获取用户名,密码
                dic1 = {}
                with open('register.text', encoding='utf-8', mode='r+') as f:  # 读写模式,先读后写,读并追加
                    for line in f:
                        if line != '\n':
                            line_list = line.strip().split('|')
                            dic1[line_list[0]] = line_list[1]  # 如果有空行,列表元素为空,会报错。
                    return dic1


            def register():  #注册
                user_dict = get_user_pwd()
                print(user_dict)
                while 1:
                    username = input('请输入用户名:').strip()
                    password = input('请输入密码:').strip()
                    password_md5 = _md5_(password)  # 对密码加密
                    if username not in user_dict:
                        with open('register.text', encoding='utf-8', mode='a') as f:
                            f.write(f'\n{username}|{password_md5}')
                            print('注册成功')
                            return True
                    else:
                        print('用户名已经存在')
            # register()


            def login():  #登录
                user_dict1 = get_user_pwd()
                count = 0
                while count < 3:
                    username = input('请输入用户名:').strip()
                    password = input('请输入密码:').strip()
                    password_md5 = _md5_(password)
                    if username in user_dict1 and password_md5 == user_dict1[username]:
                        print('登陆成功')
                        return True
                    else:
                        print('用户名或密码错误')
                        count += 1
            # login()
            
            
            
            # 普通加密
             
             # 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
            
            比如你在一家公司,公司会将你们所有的密码在md5之前增加一个固定的盐,这样提高了密码的安全性。但是如果黑客通过手段窃取到你这个固定的盐之后,也是可以破解出来的。所以,我们还可以加动态的盐。


            # 动态的盐
             s2 = '19890425'
             ret = hashlib.md5('太白金星'[::2].encode('utf-8'))   #比如用户名切片,针对于每个账户,每个账户的盐都不一样
             ret.update(s2.encode('utf-8'))
             print(ret.hexdigest())  # 84c31bbb6f6f494fb12beeb7de4777e1


            # sha系列  金融类,安全类.用这个级别.
            hahslib模块是一个算法集合,他里面包含很多种加密算法,刚才我们说的MD5算法是比较常用的一种加密算法,一般的企业用MD5就够用了。但是对安全要求比较高的企业,比如金融行业,MD5加密的方式就不够了,得需要加密方式更高的,比如sha系列,sha1,sha224,sha512等等,数字越大,加密的方法越复杂,安全性越高,越不容易破解,但是效率就会越慢。
            
                 s2 = '198fdsl;fdsklgfjsdlgdsjlfkjsdalfksjdal90425'
                 ret = hashlib.sha3_512()
                 ret.update(s2.encode('utf-8'))
                 print(ret.hexdigest())  # 4d623c6701995c989f400f7e7eef0c4fd4ff15194751f5cb7fb812c7d42a7406ca0349ea3447d245ca29b48a941e2f2f66579fb090babb73eb2b446391a8e102


                 #也可加盐
                 ret = hashlib.sha384(b'asfdsa')
                 ret.update('taibaijinxing'.encode('utf-8'))
                 print(ret.hexdigest())

                 # 也可以加动态的盐
                 ret = hashlib.sha384(b'asfdsa'[::2])
                 ret.update('taibaijinxing'.encode('utf-8'))
                 print(ret.hexdigest())



            2.文件的校验
            

             linux中一切皆文件: 文本文件,非文本文件(我们普通的文件,是文件,视频,音频,图片,以及应用程序等都是文件 )
             无论你下载的视频,还是软件(国外的软件),往往都会有一个md5值,往往都带有一个MD5或者shax值,当我们下载完成这个应用程序时你要是对比大小根本看不出什么问题,你应该对比他们的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. 密码的加密 ,文件的校验
    2.  

相关教程