Python基础学习笔记(二)

一、程序结构

  1. 模块 Module

    1. 定义:包含一系列的数据、函数、类的文件,通常以.py结尾;

    2. 作用:让一些相关的数据,函数,类有逻辑的组织在一起,是逻辑结构更加清晰。利于多人合作开发;

    3. 导入:可以跨模块访问类,本质是创建变量接收其他的模块/模块中的成员。

      1. 方式一:直接导入整个模块,使用模块名/别名调用成员;
        • import 模块名( as 别名)
      2. 方式二:导入部分类、方法或变量到当前作用域中,直接使用导入的成员;
        • from 模块名 import 方法名/变量名( as 别名)
      3. 方式三:导入模块的所有成员,需注意是否与自身成员冲突;
        • from 模块名 import * ( as 别名)
    4. 模块变量:

      • __all__ 变量:定义可导出成员,仅对 from 模块 import * 语句有效;

      • __doc__ 变量:文档字符串,注释;

      • __file__ 变量:模块对应的文件路径名;

      • __name__ 变量:模块自身名字,可以判断是否为主模块;

        • 被导入的模块,打印的是真实的模块名字;

        • 第一次运行的模块,打印的是 __main__ ,是主模块;

          # main为程序的入口
          # 如果当前模块是主模块,代码执行,否则不执行
          if __name__ == "__main__":
              print("执行的代码")
          
    5. 加载过程:

      1. 在模块导入时,模块中的所有语句都会执行。
      2. 如果一个模块已经导入,再次导入时不会重复执行;
    6. 模块分类:

      1. 内置模块:builtins,在解析器的内部可以直接使用;
      2. 标准库模块:安装Python时已安装且可直接使用;
      3. 第三方模块:需要自己安装,通常为开源;
      4. 自定义模块:自己编写的模块,可作为其他人的第三方模块;
  2. 包 package

    1. 定义:将模块以文件夹的形式进行分组管理。

    2. 作用:让一些相关组织在一起,使逻辑结构更加清晰。

    3. 导入:

      • 方式一:import 包名.模块名( as 别名)

      • 方式二:from 包名.模块名 import 方法名/变量名( as 别名)

      • 方式三:from 包名.模块名 import * ( as 别名)

        • 注意:如果导入的是一个包,那么需要在包的 __init__.py 模块中设置 __all__ 属性;

          __init__.py		# 设置导入的内容
          	__all__ = ["Student"]
          
          from com.it.package import *
          
          Student.fun01()
          Student.Student(23).fun02()
          
      • __init__.py 的作用:

      1. 包内必须存在的文件,象征当前文件夹是一个包;
      2. 导入的时候会自动调用执行 __init__.py 模块
      • 搜索顺序:内置模块 sys

        • 导入模块成功的唯一条件:
          • sys.path + 导入路径 可以正确定位模块的位置;
  3. 标准库模块

    1. time 时间:
      • time.time():当前时间戳,1970年1月1日到现在经过的秒数;
      • time.localtime():时间元组,年月日时分秒,星期,年的天数,夏令时偏移量;
      • time.localtime(时间戳):接收时间戳的参数,可以将时间戳转变为一个时间元组;
      • time.mktime(时间元组):可以将一个时间元组转变为一个时间戳;
      • time.strftime(“%Y年%m月%d日”, 时间元组):按指定规则,格式化时间元组;
      • time.strptime(时间字符串, “%Y年%m月%d日”):按指定规则,转换为时间元组;

二、异常处理

  1. 异常:父类 Exception

    1. 定义:运行时检测到的错误;
    2. 现象:当异常发生时,程序不会继续运行,而是转到函数的调用语句;
    3. 常见的异常类型:
      • NameError:名称异常,变量未定义;
      • TypeError:类型异常,不同类型的数据进行运算;
      • IndexError:索引异常,索引超出范围;
      • AttributeError:属性异常,对象没有对应名称的属性;
      • KeyError:没有对应名称的键;
      • NotImplementedError:未实现异常,尚未实现的方法;
  2. 处理:

    1. 作用:将程序由异常状态转为正常流程;

    2. 统一处理:except 可以接收一个异常对象,使用 as 起别名,可调用异常的内部方法;

      def calculate():
          try:
              10 / int(input("请输入整数:"))
          except:
              print("出错了")
              
      def calculate2():
          try:
              10 / int(input("请输入整数:"))
          except Exception as e:	# 起别名
              print(e.args[0])
      
    3. except语句,针对不同的错误,做相应的处理:

      def calculate():
          try:
              10 / int(input("请输入整数:"))
          except ValueError:
              print("输入的不是整数")
          except ZeroDivisionError:
              print("不能除零")
      
    4. else语句,配合expect使用,没错误时执行:

      def calculate():
          try:
              10 / int(input("请输入整数:"))
          except ValueError:
              print("输入的不是整数")
          else:
              print("没有错误时执行,搭配except使用,不能单独存在")
      
    5. finally语句:

      def calculate():
          try:
              10 / int(input("请输入整数:"))
          except ValueError:
              print("输入的不是整数")
          finally:
              print("一定会执行的语句")
      
  3. raise 语句

    1. 作用:主动抛出异常,让程序进入异常状态;
    2. 目的:人为抛出异常,快速传递错误信息,比层层 return 速度要快;
    3. 格式:raise Exception(“错误信息”)
    4. 自定义异常类:继承Exception类,封装异常的数据;

三、迭代

每一次对过程的重复称为一次迭代,每一次迭代的结果将会作为下一次迭代的初始值;

:for循环一次,计算一个,返回一个;所有不会撑爆内存。

  1. 可迭代对象 iterable

    for循环原理:可迭代对象具有__iter__()方法;

    • __iter__():获取迭代器对象,可迭代对象 (集合、元组等) 调用;
    • __next__():获取下一个元素,迭代器对象 (iterator) 调用;
    iterator = list01.__iter__()
    
    while True:
        try:
            print(iterator.__next__())
        except StopIteration:
            break
    
  2. 迭代器对象 iterator

    iterator:可迭代对象具有__iter__()方法,为迭代对象计数,长度大于可迭代对象停止迭代;

  3. yield 关键字

    1. 程序执行过程:

      • 调用 __iter__() 程序不执行;

      • 调用 __next__() 才会执行;

      • 执行至 yield 暂时离开;

      • 再次调用 __next__() 继续执行离开时的后续代码;

    2. 执行原理:

      • 程序将 yield 前面的代码定义到next方法中;
      • 程序将 yield 后面的代码作为next的返回值;
      • yield 不会停止代码的执行,故 yield 后面的代码也执行;
      class MyRange2:
          def __init__(self, data):
              self.__data = data
      
          def __iter__(self):
              begin = 0
              while self.__data > begin:
                  yield begin
                  begin += 1
      
      
      for item in MyRange2(5):
          print(item)
      

五、生成器 generator

  1. 定义:能够动态(循环一次)提供数据的可迭代对象;

  2. 作用:循环过程中,根据某种算法推算数据,从而节省内存空间。数据量越大越明显;

  3. 以上作用也称为 延迟操作 / 惰性操作,通俗的讲就是在需要的时候才计算结果,而不是一次性计算出所有结果;

  4. 内置生成器:

    1. 枚举函数 enumerate()
      1. 语法:
        • for 变量 in enumerate(可迭代对象)
        • for 索引,元素 in enumerate(可迭代对象)
      2. 作用:遍历可迭代对象时,可以将索引和元素组合为一个元组;
    2. 压缩函数 zip():
      1. 语法:
        • for 变量 in zip(可迭代对象1,可迭代对象2)
        • for 索引,元素 in zip(可迭代对象,可迭代对象2)
  5. 生成器函数:

    1. 定义:含有 yield 关键字的语句的函数,返回值为生成器对象;

    2. 语法:

      • 创建:__iter__() 函数,内部加入 yield 关键字

        def get_list():		# 生成新列表,每项比原列表的值大10
            for item in list01:
                yield item +10
        
      • 调用:for循环语句自动调用

  6. 生成器表达式:

    1. 语法:

      • 格式一:变量 = ( yield 返回值 for元素 in 可迭代对象)

      • 格式二:变量 = ( yield 返回值 for元素 in 可迭代对象 if条件)

        generate01 = (item +10 for item in list01)
        
        for item in generate01:
            print(item)
        
    2. 惰性操作:

      • 优点:节省内存;
      • 缺点:不能灵活访问每一项,无法使用索引、切片操作;
    3. 立即操作:

      • 优点:灵活访问每一项,可以使用索引、切片操作;
      • 缺点:占用内存;
    4. 惰性操作 ==> 立即操作:

      • 将生成器结果转换为容器(列表、元组、集合等)
      • 例如:list01 = list(item +10 for item in list01)

六、函数式编程:

  • 定义:用一系列函数解决问题。

  • 理论支柱:

    • 函数可以赋值给变量,复制后变量绑定函数;
    • 允许将函数作为参数传入另一个函数;
    • 允许函数返回另一个函数;
  • 高阶函数:将函数作为参数或返回值的函数。

    • 内置高阶函数:
    • map(函数,可迭代对象):根据可迭代对象,根据每一项映射出新的可迭代对象;
      • filter(函数,可迭代对象):过滤出符合条件的元素;
      • sorted(可迭代对象, key = 函数,reverse = 布尔值):排序,无需通过返回值传递结果
      • max(可迭代对象, key = 函数):最大值
      • min(可迭代对象, key = 函数):最小值
  1. 函数作为参数:

    1. 传入时不能带括号,否则直接会执行,而是将函数名传入,这样即可在方法内部再执行;
  2. lambda表达式(匿名函数):

    1. 格式:lambda 参数:方法体,例如:lambda num:num == 0
    2. 作用:
      • 作为实参传递给函数,语法简洁优雅,可读性高;
      • 调用完毕立即销毁,减少代码耦合度;
    3. 注意:
      • 若无形参可不填;
      • 不能进行赋值操作;
      • 方法体只支持一行语句;
    4. 变体:
      • 单个参数:lambda a: a==0
      • 多个参数:lambda a, b, c: a==b==c
      • 没有参数:lambda : '无参数'
      • 没参数,没返回值:lambda a: print('无返回值')
  3. 外部嵌套作用域:Enclosing

    def fun01():
        a = 10		# 局部变量,外部嵌套变量
        def fun02():
            b = 20		# 局部变量
            print(a)		# 此时可读取外部嵌套变量,却不能修改
            nonlocal a		# 使用nonlocal声明外部嵌套变量后,才可修改,与global类似
            a = 20		# 修改外部嵌套变量
    
  4. 函数作为返回值:

    逻辑连续,当内部函数被调用时,不脱离当前的逻辑;

    1. 闭包:

      1. 闭包说明:

        1. 非嵌套函数:调用时,在内存中开辟栈帧;函数执行完毕,栈帧释放,局部变量销毁;
        2. 嵌套函数:外部函数执行完毕后,不会释放栈帧,销毁局部变量;而是留给内部函数继续使用;
      2. 三要素:

        • 必须有一个内嵌函数;
        • 内嵌函数必须引用外部函数中的变量;
        • 外部函数返回值必须是内嵌函数;
      3. 语法:

        def 外部函数名(参数):
            外部变量
            def 内部函数名(参数):
                nonlocal 外部变量		# 声明外部函数,而不是新创建一个
                使用外部变量
        
      4. 优缺点:

        1. 优点:内部函数可以使用外部函数;
        2. 缺点:外部变量会一直存在于内存中;
      5. 作用:为了实现函数装饰器;

      6. 应用:

        def fun01(money):
            def fun02(num):
                nonlocal money
                if money > num:
                    money -= num
                    print("余额:", money)
                else:
                    print("余额不足")
        
            return fun02		# 返回值为一个函数
        
        
        fun03 = fun01(1000)		# 调用函数1,返回值为一个函数fun03
        fun03(200)			# 调用返回的函数,这时,局部变量不会销毁
        fun03(400)			# 调用返回的函数
        fun03(500)			# 调用返回的函数
        
    2. 装饰器 decorator:拦截原函数,使其功能更强大

      1. 定义:在不改变原函数的调用以及内部代码的情况下,为其添加新的功能;

      2. 语法:

        def 装饰器名称(func):
            def 内嵌函数名称(*args, **kwargs):
                '需要添加的新功能'
            	return func(*args, **kwargs)
        	return 内嵌函数名称
        
        # 调用
        原函数上添加注解:@装饰器名称
        
      3. 例如:

        def add_name_to_say(func):		# 装饰器方法
            def wrapper(*args, **kwargs):
                print(func.__name__)
        
                return func(*args, **kwargs)
        
            return wrapper
        
        
        @add_name_to_say		# 调用装饰器
        def say_hello():
            print("hello")
        
        
        @add_name_to_say
        def say_goodbye():
            print("goodbye")
        
        
        say_hello()
        say_goodbye()
        

七、python语言基础 (总结) :

  1. 内存管理机制:

    • 引用计数:

      1. 每个变量存储对象地址时,引用计数都会自增1;

      2. 每个变量与对象引用断开时,引用计数都会自减1;

      3. 如果引用计数为0,对象则被释放;

      • 缺点:解决方式:标记清除
        • 循环引用:垃圾引用垃圾,导致无法释放内存;
    • 标记清除:扫描内存,查看是否存在无法访问的内存空间;

      • 缺点:耗时长,解决方式:分代回收
    • 分代回收:每代的内存告急时,采用标记清除,将有用的数据升至下一代;

      1. 新生代:存储数据时开辟空间;
      2. 中年代:新生代满时,将有用的数据存放至此;
      3. 老年代:中年代满时,将有用的数据存放至此;
    • 内存优化:

      1. 尽少的产生内存垃圾;
      2. 对象池
      3. 手动回收:慎用!
  2. 对象池:

    1. 每次创建对象时,都会判断池中是否具有相同的对象;有,拿来用。没有,创建;
    2. 优点:提高内存的利用率;
  3. 函数参数:

    1. 实际参数:调用函数时

      1. 位置实参:函数名(参数一,参数二)
        1. 序列实参:函数名(*序列)
      2. 关键字实参:函数名(参数一 = 数据1,参数二 = 数据2)
        1. 字典实参:函数名(**字典)
    2. 形式参数:创建函数时

      1. 位置形参:def 函数名(形参1,形参2)

        1. 星号元组形参:def 函数名(*args)
      2. 命名关键字形参: def 函数名(*,形参1,形参2)

        ​ def 函数名(*args,形参1,形参2)

        1. 双星号字典形参:def 函数名(**kwargs)
      3. 默认参数:def 函数名(形参一 = 默认值2,形参二 = 默认值2)

  4. 面向对象:OOA(分析)、OOD(设计)、OOP(编程)

    1. 软件项目生命周期:
      1. 前期 -> 市场:招标、投标
      2. 中期 -> 开发:
        • 项目启动 --> 项目立项报告
        • 需求调研 --> 需求规格说明书、需求分析说明书
        • 设计开发 -->
          • 概要设计:架构、系统功能设计、关键类、关键算法
          • 详细设计:子类、类成员、数据、业务细节
          • 编码:
        • 整体测试 --> 功能、性能
        • 试运行
        • 项目验收
      3. 后期 -> 服务:运维
  5. python核心

    1. 迭代器 --> 生成器(惰性/延迟)
    2. 函数式编程:
      • 函数作为参数:将核心逻辑传入函数
      • 函数作为返回值:闭包 --> 装饰器
        • 不改变原有功能,在原基础上增加性能
        • 装饰器:
          • 核心思想:拦截旧功能
          • 新功能与旧功能包装在一起

八、IO

  1. 定义:数据流的输入输出,在内存中进行数据交换的操作,一般认为是IO操作;

  2. 程序分类:

    • IO密集型程序:IO操作较多;
    • 计算密集型程序:计算操作较多;
  3. 文件

    1. 格式编码角度分为:文本文件、二进制文件
    2. python中把文件视为一种类型的对象;
  4. 字节串 (bytes)

    1. python3中引入字节串的概念;
    2. 字节串以字节序列值表达数据,更方便处理二进制数据;
    3. 格式:b'字符串',仅支持ASCII,例如:s = b'abc'
    4. 格式:b'字符串'.encode(),encode() 将字符串(str)转换 字节串(bytes),decode()反之;
  5. 文件读写

    1. 对文件读写的基本操作:打开文件、读写文件、关闭文件。

      • 打开文件:open(file_name, access_mode='r', buffering=-1),返回一个文件操作对象;
        • 参数一:file_name,文件名称;
        • 参数二:access_mode,打开文件的方式,默认为 ‘r’ ;
          • r:以读的方式打开,文件必须存在。
          • w:以写的方式打开,无法获取文件内容。文件不存在则创建;文件存在则清空文件内容。
          • a:以追加模式打开,不会清空文件内容,而是在后面继续写。
          • r+:以读写模式打开,文件必须存在。
          • w+:以读写模式打开。
          • a+:以读写模式打开,追加模式。
          • rb:以二进制读模式打开,同r。
          • wb:以二进制写模式打开,同w。
          • ab:以二进制追加模式打开,同a。
          • rb+:以二进制读写模式打开,同r+。
          • wb+:以二进制读写模式打开,同w+。
          • ab+:以二进制读写追加模式打开,同a+。
        • 参数三:buffering,默认-1,使用系统默认的缓冲机制;1 指行缓冲。
          • 缓冲区刷新条件:
            1. 缓冲区被写满;
            2. 程序执行结束,或文件对象被关闭;
            3. 行缓冲遇到换行符( “\n” );
            4. 主动调用 flush() 函数;
    2. 说明:

      1. 文本文件:可以用文本或二进制方式打开;
      2. 二进制文件:必须使用二进制方式打开;
    3. 文件的操作:

      1. 打开文件:

        file01 = open('file/test.txt', 'r') # 只读,文件必须存在
        file01 = open('file/test.txt', 'w') # 只写,不存在则创建
        file01 = open('file/test.txt', 'a') # 追加,append
        
      2. 读写操作:

        # 写入文件, 区别writelines(),writelines()可以写入多行,write()只能写入一行
        file01.write(str01)
        file01.writelines(str01)
        
        # 读取文件
        print(file01.read(5))  # 读取5个字符, 不包括换行符, 不给参数默认读取全部
        print(file01.readline())  # 读取一行,换行符也读取,但是不会返回换行符,只返回一行,如果要返回换行符,可以使用readlines()
        print(file01.readlines())  # 读取所有行,返回一个列表,每一行作为一个元素
        
        # 迭代特性
        for line in file01:
            print(line)  # 一次读取一行
        
      3. 关闭文件:

        file01 = open('file/新建文本文档.txt', 'r')
        file01.close() # 关闭资源
        
      4. with语句块:(语句块结束,文件则自动销毁,无需调用close方法)

        # 等价于 f = open('file/test.txt', 'r')
        with open('file/test.txt', 'r') as f:
            data = f.read()
            print(data)
        
      5. 文件拷贝:

        rf = open('C:/Users/范亚鑫/Desktop/20000000.xlsx', 'rb')
        wf = open('C:/Users/范亚鑫/Desktop/40000000.xlsx', 'wb')
        
        while True:
            line = rf.read(1024)
            if not line:
                break
            wf.write(line)
        
        rf.close()
        wf.close()
        
    4. 文件偏移量:

      1. 定义:对文件进行操作时,系统会自动生成一条记录,记录了对文件的一系列操作,例如读写的位置,下次操作会自动从记录的位置进行操作。
      2. 注意:
        • 读和写用的是同一个偏移量;
        • 每次调用open函数时,偏移量都将刷新,r / w 偏移量处于文件开头,a 偏移量处于末尾;
      3. 基本操作:
        • tell() 函数:获取当前的偏移量大小;
        • seek(offset, whence) 函数:更改文件偏移量的位置;whence必须二进制可选 1 / 2;
          • offset:正数向后偏移,负数向前偏移
          • whence:可省,默认0;0指文件开头算起;1指当前位置开始,2指文件末尾算起;
        • 空洞文件:指文件内容很小,却占用了很大空间,用于占用内存,为后续操作做准备;
    5. 文件描述符:

      • 定义:系统中每一个IO操作都会分配一个整数编号,这个编号就是文件描述符;
      • fileno() 函数:获取文件描述符;
    6. 文件管理函数:os模块

      • os.path.getsize():获取文件大小;
      • os.listdir(‘path’):path为目录名,获取目录内的文件列表;
      • os.path.exists():判断文件是否存在;
      • os.path.isfile(‘filename’):filename为文件名,判断文件是否为普通文件;
      • os.remove(‘filename’):filename为文件名,删除文件

九、网络编程基础

1.TCP套接字(面向连接的可靠协议)

  1. 服务端:

    import socket
    
    # 1. 创建套接字,默认参数就是socket.AF_INET, socket.SOCK_STREAM,可以省略
    sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    # 2. 绑定地址
    server_addr = ('127.0.0.1', 8080)
    sk.bind(server_addr)
    
    # 3. 设置监听
    sk.listen(3)
    
    # 4. 等待接收客户端连接
    conn, addr = sk.accept()
    
    # 5. 收发消息
    res = conn.recv(1024)
    print(res.decode())		# 转码为字符串
    # 发送消息
    conn.send(b'Success!\r')
    
    # 6.关闭
    conn.close()
    sk.close()
    
  2. 客户端:

    import socket
    
    # 1. 创建套接字,默认参数就是socket.AF_INET, socket.SOCK_STREAM,可以省略
    sk = socket.socket()
    
    # 2. 连接服务器
    server_addr = ('0.0.0.0', 8080)
    sk.connect(server_addr)
    
    # 3. 收发消息
    msg = input('send >>>')
    sk.send(msg.encode())
    # 接收消息
    res = sk.recv(1024)
    print('result: ', res.decode())
    
    # 4. 关闭
    sk.close()
    

TCP粘包

  1. 原因:tcp以字节流方式传输,没有消息边界。多次发送的消息被一次接收,此时就会形成粘包。
  2. 影响:如果每次发送内容是一个独立的含义,需要接收端独立解析此时粘包会有影响。
  3. 解决方式:
    1. 人为控制消息边界;
    2. 控制发送速度;

2.UDP套接字(面向无连接的不可靠协议)

  1. 服务端:

    from socket import *
    
    # 1. 创建套接字,注意,参数二需改为SOCK_DGRAM
    sk = socket(AF_INET, SOCK_DGRAM)
    
    # 2. 绑定服务地址
    server_addr = ('127.0.0.1', 8080)
    sk.bind(server_addr)
    
    # 3. 收发消息,接收所有人的消息
    while True:
        try:
            data, addr = sk.recvfrom(1024)
            print('recv<<<', data.decode())
    
            # 回复消息到发送者
            send_msg = '收到来自%s消息>>>' % ''.join(str(item) for item in addr)
            sk.sendto(send_msg.encode(), addr)
        except Exception as e:
            print(e)
            break
    
    # 4.关闭连接
    sk.close()
    
  2. 客户端:

    from socket import *
    
    # 1. 创建套接字,注意,参数二需改为SOCK_DGRAM
    sk = socket(AF_INET, SOCK_DGRAM)
    
    server_addr = ('127.0.0.1', 8080)
    
    # 3. 收发消息,接收所有人的消息
    while True:
        try:
            # 给服务器发消息
            msg = input('msg===')
            if not msg:
                break
            sk.sendto(msg.encode(), server_addr)
    
            # 接收服务器消息
            data, addr = sk.recvfrom(1024)
            print('from server: ', data.decode())
        except Exception as e:
            print(e)
            break
    
    # 4.关闭连接
    sk.close()
    

3.总结:

  1. TCP和UDP区别:

    1. 流式套接字是以字节流形式传输,数据报套接字以数据报形式传输;
    2. tcp套接字会有粘包,udp套接字有消息边界不会粘包;
    3. tcp套接字保证消息的完整性,udp套接字则不能;
    4. tcp套接字依赖 listenaccept 建立连接才能收发消息,udp套接字则不需要;
    5. tcp套接字使用 sendrecv 收发消息,udp套接字使用 sendtorecvfrom
  2. 套接字属性

    1. 套接字类型:sk.type
    2. 套接字地址类型:sk.family
    3. 套接字绑定地址:sk.getsockname()
    4. 文件描述符:sk.fileno()
    5. 获取客户端地址:conn.getpeername()
    6. 设置套接字选项:sk.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1),表示重启后端口立即重用;

4.struct模块数据打包

  1. 原理:将一组简单数据进行打包,转换为bytes格式发送。或者将一组bytes格式数据,进行解析。

  2. 使用 Struct(fmt):生成结构体对象,参数为定制的数据结构;

  3. 函数:

    • pack:将一组数据按照指定格式打包转换为bytes;
    • unpack:将bytes字节串按照指定的格式解析;
  4. 示例:

    import struct
    
    # 'i5sf'解释:i:参数一为int类型;5s:参数二为str类型,长度为5;f:参数三为float类型
    st = struct.Struct('i5sf')
    data = st.pack(5, b'Hello', 4.3)
    res = st.unpack(data)
    
    # 方式二
    data = struct.pack('i5sf', 5, b'Hello', 4.3)
    res = struct.unpack('i5sf', data)
    

5.HTTP协议

  1. 定义:超文本传输协议。用于网页获取,数据传输;
  2. 特点:
    • 应用层协议,传输层使用tcp传输;
    • 简单灵活,很多语言都有HTTP专门接口;
    • 无状态,协议不记录传输内容;
    • http1.1 支持持久连接,丰富了请求类型;
  3. 请求过程:
    • 客户端(浏览器)通过tcp传输,发送http请求给服务端;
    • 服务端接收到http请求后进行解析;
    • 服务端处理请求内容,组织响应内容;
    • 服务端将响应内容以http响应格式发送给浏览器;
    • 浏览器接收到响应内容,解析展示;
  4. 请求request
    • 请求行:请求的类别和请求内容,由请求方法、请求内容、http协议版本组成;
    • 请求头:对请求的解释和描述;
    • 空行
    • 请求体:请求参数或提交内容;
  5. 响应response
    • 响应行:反馈响应情况,由http版本信息、响应码、附加信息组成;
    • 响应头:响应内容的描述;
    • 空行
    • 响应体:响应内容信息;
  • 10
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风於尘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值