<
  • 主题:
  • + -
  • 清除背景
  • 禁用背景
目 录
  1. 1. 关于Python
    1. 1.1. 引言
      1. 1.1.1. 常用命令选项
      2. 1.1.2. 交互模式
      3. 1.1.3. 脚本文件
      4. 1.1.4. 缩进
      5. 1.1.5. 传入参数
    2. 1.2. 数据模型
      1. 1.2.1. 对象、值与类型
      2. 1.2.2. 内置类型
      3. 1.2.3. 数据类型分类
      4. 1.2.4. 可变对象与深拷贝、浅拷贝
  2. 2. 数值
    1. 2.0.1. int整型
    2. 2.0.2. 布尔值
    3. 2.0.3. float浮点数
    4. 2.0.4. 复数
  • 3. NoneType
  • 4. 序列
    1. 4.1. 序列的操作
      1. 4.1.1. 通用操作
      2. 4.1.2. 可变序列类型支持
      3. 4.1.3. 不可变序列类型支持
    2. 4.2. list列表
      1. 4.2.1. 创建列表
      2. 4.2.2. 列表操作
      3. 4.2.3. sort方法
    3. 4.3. tuple元组
      1. 4.3.1. 创建元组
      2. 4.3.2. 元组操作
    4. 4.4. range对象
    5. 4.5. str字符串
      1. 4.5.1. 创建字符串
      2. 4.5.2. 字符串前缀
      3. 4.5.3. 字符串拼接
      4. 4.5.4. 常用字符串操作
      5. 4.5.5. 格式化
        1. 4.5.5.1. format方法
        2. 4.5.5.2. f-string
      6. 4.5.6. t-string
      7. 4.5.7. 编码
        1. 4.5.7.1. 字符与码点
        2. 4.5.7.2. 字符编码
        3. 4.5.7.3. 编码/解码
      8. 4.5.8. 其他字符表示
    6. 4.6. bytes
      1. 4.6.1. 创建bytes
      2. 4.6.2. bytes与str
    7. 4.7. bytearray
      1. 4.7.1. 创建bytearray
    8. 4.8. memoryview
      1. 4.8.1. 创建memoryview
      2. 4.8.2. 属性
      3. 4.8.3. 操作
  • 5. 集合
    1. 5.0.1. 特点
    2. 5.0.2. 集合的底层实现
    3. 5.0.3. 集合操作
  • 5.1. 可变集合 set
    1. 5.1.1. 创建 set
    2. 5.1.2. 可变集合的操作
  • 5.2. 冻结集合frozenset
    1. 5.2.1. 创建frozenset
  • 6. 映射类型
    1. 6.1. 字典dict
      1. 6.1.1. 字典的特点
      2. 6.1.2. 字典的底层实现
      3. 6.1.3. 创建字典
      4. 6.1.4. 字典操作
  • 7. 表达式
    1. 7.0.1. 标识符
    2. 7.0.2. 数值运算
    3. 7.0.3. 位运算
    4. 7.0.4. 比较运算
    5. 7.0.5. 身份比较与成员测试
    6. 7.0.6. 逻辑运算
    7. 7.0.7. 条件表达式(三元运算符)
    8. 7.0.8. 海象运算符
    9. 7.0.9. 解包
  • 7.1. 推导式
    1. 7.1.1. 列表/集合/字典推导式
    2. 7.1.2. 生成器表达式
  • 7.2. 语法练习题
  • python(上)

    字数:39005 写于:2022-09-05
    最新更新:2022-09-05 阅读本文预计花费您112分钟
    整理自《Fluent Python》-Luciano Ramalho,python官网的tutorial和reference

    关于Python

    引言

    Python语言名字的来源和蟒蛇(python)没有直接关系,而是来自英国著名喜剧团体 Monty Python(巨蟒剧团),Python 之父 Guido van Rossum 是 Monty Python 的粉丝

    常用命令选项

    python [选项] [脚本文件]

    • -c "command":快速执行一段python代码
    • -m 模块名:通过模块导入机制运行模块,可以将模块作为主程序执行
    • -i 脚本名:执行脚本后进入交互式解释器
    • -u 禁用标准/错误输出的缓冲,常用于脚本的输出被重定向到管道、文件的情况,如:python -u test.py > output.txt。默认情况下,这些输出会进入缓冲区,并在缓冲区积累一段时间后才真正写入文件(以块形式缓冲输出),如果此时在tail实时监听输出,可能导致看到输出不及时,-u可以使得解释器更积极输出信息
    • -O 启用基本优化,会进行以下
      • 移除所有 assert 语句,不再执行断言语句
      • 将__debug__ 置为 False,编译器会直接移除字节码中 if __debug__: 内部的代码
      • 将字节码缓存在不同目录/文件名下,文件名后缀为.opt-1.pyc,表示优化级别为1
    • -OO:具备-O所有行为,并额外移除所有文档字符串(docstring)
    • -v 查看版本
    • -h 帮助

    交互模式

    类Unix系统中,Python解释器默认安装在/usr/local/bin/目录下,在python shell中:

    • 主提示符为>>>
    • 次提示符为...
    • 退出解释器:在主提示符中,输入EOF文件结束符(Unix中为Control-D,Windows中为Control-Z)并回车,或使用python命令quit(),该方法退出状态码为 0
    • 交互模式下,上次输出的表达式会赋给变量_,如:num + _会捕获上次运算的结果并加到num变量中
    • 可以在OS环境变量中添加 PYTHONSTARTUP环境变量,让其指向一个文件,每次交互式 Python shell 启动时,会首先执行其中的代码,类似于 Unix shell 的 .profile 功能

    Python 3.13+ 支持

    • 彩色Python shell
    • 可以直接通过 exit和quit命令提出 shell
    • F1 相当于执行 help ,进入帮助页面,可以直接输入命令、模块获得帮助
    • F2 打开历史命令,相当于Linux中的 history
    • F3 进入粘贴模式,方便粘贴大段代码,避免逐行执行导致的缩进/语法错误

    脚本文件

    默认情况下,Python源码文件的编码是UTF-8,如果要修改文件的编码方式,则需要进行编码声明:

    • 在脚本文件第一行添加以下特殊注释
      # -*- coding: 编码方式 -*-
    • 如果脚本第一行为UNIX shebang,则编码声明要写在文件的第二行
      #!/usr/bin/env python3 # -*- coding: 编码方式 -*-

    缩进

    • Python 使用缩进表示语句块的层级结构(而非大多数语言使用的大括号{ }),缩进属于 Python 语法的一部分,这是Python的一大特色
    • Python语句(逻辑行)开头的空格和制表符用于确定该行的缩进层级。具有相同缩进层级的语句属于同一个语句块。源代码中应保持缩进方式一致,文档建议不要混用制表符(Tab)和空格。通常建议统一使用4 个空格表示一级缩进,并交由编辑器自动处理缩进

    传入参数

    解释器读取命令行参数,把脚本名与其他参数转化为字符串列表存到sys 模块的argv 变量里,使用方法:

    • 导入模块import sys
    • 通过argv[索引值]访问元素,未给定输入参数时,sys.argv[0] 是空字符串
    • 文档使用/和*标识函数的参数应该以什么方式传入:
      • /代表 / 前的参数为位置参数,如:def foo(a, b, /, c)中,可以通过foo(1, 2, c=3)和foo(1, 2, 3)传参,而foo(a=1, b=2, c=3)是错误的
      • *代表 * 后面的参数只能按关键字传参,如:def bar(a, *, b)可以通过bar(1, b=2)调用,但bar(1, 2)是错误的

    数据模型

    对象、值与类型

    Python将各种类型的数据抽象为了对象(Object),Python程序中的所有数据都是由对象或对象间关系来表示的,每个对象都有三个基本属性:标识号(identity)、类型(type)和值(value)。Python中的对象被创建后,其标识号在其生命周期内不会改变,标识号在CPython中可以理解为该对象在内存中的地址

    • 可以使用is运算符比较两个对象的标识号是否相同
    • id()函数会返回代表该对象标识号的整数
    • type()函数会返回该对象的类型,与编号一样,一个对象的类型也是不可改变的
    e.g.与静态语言不同,python中的数据都是对象 如:在C语言创建一个整型变量 int a = 14 该语句会开辟一个4字节的整数存储空间 而在python中同样创建一个整型变量 a = 14 python解释器会为其创建一个int类型的对象:
    { int对象 type:int, value:14, id:140732635804456, ..... }
    它的占用不再仅仅是4字节,而是一整个python对象大小(但由此带来的好处是python可以动态调整值的位数,因此python支持的数值将会很大而不再限于int支持大小,也不需要开发者手动声明long long) 创建完Python对象后,名称(name)a 将指向(绑定到)该对象以完成赋值 此时,再创建一个整型变量 b = 14,名称b也会指向该对象,即对值为14的int对象的引用会被重用,使变量a,b指向同一个对象,因此执行:
    a is b # 将返回True id(a) #输出140732635804456 id(b) #同样输出140732635804456
    之后修改 a = 10,由于 int 是不可变对象,因此将创建一个新的 int 对象,再让 a 指向该对象,而不是修改原对象值

    内置类型

    Python中的数据类型可以从“对象支持什么操作”这一数据模型(data model)角度进行分类,相同类型的数据通常支持一组通用的公共操作(如:切片访问)

    • None:该类型只有None一种取值,在许多情况下它被用来表示空值,如:未显式指明返回值的函数将返回 None,其逻辑值为假
    • 数字类型(numbers):用于表示数值,并支持相应的算术运算。Python 内置的主要数字类型包括整数(int,其中Boolean类型是int的子类)、浮点数(float)和复数(complex)
    • 序列(Sequence):有限、有序的对象集,可以通过整数索引访问元素。序列通常支持索引、切片、长度计算、成员测试、拼接和重复等通用操作。序列可以进一步分为
      • 可变序列(Mutable Sequence):可变序列在被创建后仍可被改变,包括通过下标、切片赋值或通过del语句删除,列表(list)、字节数组(bytearray)属于该类型
      • 不可变序列(Immutable Sequence):不可变序列类型的对象一旦创建就不能再改变,但如果对象包含对其他对象的引用,其中的可变对象是可以改变的(不可变序列对象可以包含可变对象,),字符串(str)、字节串(bytes)、元组(tuple)属于该类型
    • 集合(set):表示一组无序且不重复的元素,它们不能通过下标来索引。但是它们可被迭代,也可用内置函数 len() 返回集合长度。集合常见的用处是快速成员检测,去除序列中的重复项,以及进行交、并、差和对称差等数学运算,Python目前有两种内生集合类型:
      • 集合(set):属于可变集合(Mutable Set)。集合中的元素必须是可哈希的(hashable),可以添加和删除元素
      • 冻结集合(frozenset):属于不可变集合(Immutable Set),创建后不能修改,因此本身可以作为字典的键或其他集合的元素
    • 映射(Mapping):表示键(key)到值(value)的对应关系,与序列通过整数位置访问元素不同,映射通过键访问值。映射类型可以被赋值、通过del语句删除、len()函数返回长度,Python目前只有一种内生映射类型:
      • 字典(dict,全称dictionary):Python最常用的键值映射结构。字典是可变的,每个键映射到一个值;键必须是可哈希对象

    数据类型分类

    根据数据类型的其他特性,它们还能被分为

    • 可变(Mutable)类型:其Python对象创建后可以修改其内部值或内容的对象,修改不会创建新的对象,这样的类型有:list、set、dict、bytearray
    • 不可变(Immutable)类型:不可变对象在创建后其值不能被修改,如果需要得到不同的值,只能创建或取得另一个对象,再让名称重新绑定到该对象,这些类型包括: int、float、complex、bool、str、tuple、range、bytes、frozenset
    • 可迭代对象(Iterable):提供迭代器,从而能被for等语句遍历访问,它们包括:str、list、tuple、range、set、frozenset、dict、bytes、bytearray
    • 可哈希对象(Hashable):够产生稳定的哈希值,并可以作为字典的键或集合中的元素,通过来说,不可变对象通常适合成为哈希对象,它们包括:int、float、complex、bool、str、tuple(元素也必须全部可哈希)、bytes、frozenset(元素也必须全部可哈希)

    可变对象与深拷贝、浅拷贝

    可变对象的赋值 Python 中,变量在执行赋值操作时,是将名称绑定到指定的Python对象,如果两个变量相互赋值,它们将指向共同的对象 a = [1, 2, 3] b = a 此时 a 和 b 绑定到同一个 list 对象,通过 b 修改这个对象时,a 所指向的对象也发生了变化: b.append(4) print(a) # [1, 2, 3, 4] print(b) # [1, 2, 3, 4] 因为 a、b 本来就绑定到同一个可变对象,这样可变内置类型包括 list、dict、set、bytearray 等。可变对象创建后,可以通过原地操作(in-place operation)改变其内容。 不可变对象则不能通过原地操作改变自身,例如 int、float、bool、str、tuple、bytes、frozenset 等。它们本身就不支持修改操作,对不可变对象重新赋值时,是让名称重新绑定到另一个对象。
    浅拷贝 如果希望得到一个新的容器对象,可以进行浅拷贝(shallow copy): a = [1, 2, 3] b = a.copy() 此时 a 和 b 是两个不同的对象: a is b # False 修改其中一个容器本身,不会影响另一个: b.append(4) print(a) # [1, 2, 3] print(b) # [1, 2, 3, 4] 浅拷贝只复制对象本身这一层;如果容器中的元素是对其他对象的引用,则复制后的容器仍然引用原来的对象。 a = [[1, 2], [3, 4]] b = a.copy() a is b # False,a,b是两个不同的对象 a[0] is b[0] # True,但它们的元素指向一个对象 因此修改内部的可变对象时,两个容器仍然会受到影响: b[0].append(5) print(a) # [[1, 2, 5], [3, 4]] print(b) # [[1, 2, 5], [3, 4]] 常见支持 .copy() 方法的内置类型有list、dict、set 和 bytearray。这些类型的 .copy() 都产生相应的浅拷贝。 此外,对于部分支持切片的序列,使用切片也可以产生浅拷贝,例如: b = a[:]
    copy 模块与深拷贝 copy 模块同时提供深拷贝与浅拷贝方法 浅拷贝copy.copy()与上述容器的 .copy() 一样,创建一个新的外层对象,但内部引用的对象通常仍然共享。 深拷贝: b = copy.deepcopy(a) 深拷贝不仅创建新的外层对象,还会递归地复制其中引用的对象,因此嵌套的可变对象也不会与原对象共享。 a = [[1, 2], [3, 4]] b = copy.deepcopy(a) a is b # False a[0] is b[0] # False 修改b b[0].append(5) print(a) # [[1, 2], [3, 4]] print(b) # [[1, 2, 5], [3, 4]] 因此三种操作的核心区别是: a = b :不复制对象,两个名称绑定同一个对象 a = b.copy() :浅拷贝,创建新的外层对象,如果元素是一个对象仍可能共享 a = copy.deepcopy(b):深拷贝,递归复制内部对象,尽可能消除对象之间的共享

    数值

    Python中数值共有三种类型:整数、浮点数和复数,它们可由 int、float、complex类构造函数构造

    int整型

    • 字面量:整数字面量的长度没有限制,仅受可用内存的存储能力限制,Python会根据数值大小动态分配存储位数,不再有静态语言的限制
      • 可以使用下划线_对数字进行分组以增强可读性,如:100_000_000_000与100000000000是一样的,但下划线只能出现在数字之间,如:_123不是有效字面量
      • 可以使用前缀0b、0o、0x将整数指定为二进制、八进制或十六进制(A-F大小写不敏感),同时也可以在前缀之后添加下划线,如:0x_1f 是正确的,0_x1f 则是错误的
      • 非零十进制数中不允许有前导零,如:0123不是有效的字面量
    • 构造器:int(x=0, base=10)
      • 传入空参数时 int() 会创建0
      • x 可为整数、浮点数、字符串:
        • 如果是浮点数,会截断整数部分而不会四舍五入,如:int(1.999) 返回 1
        • 如果是字符串,字符串不能带有如何非数值类型的字符(可以包含正负号、空白字符、用于分组的_),否则抛出ValueError,因此推荐先 str.isdigit() 判断是否包含非数值字符 或 try/except
      • base :在x为字符串时添加,用于指定进制(2-36) ,此时字符串中允许带有A-F等多进制使用的字符,如:int("0xFF", 16)

    布尔值

    • 布尔值只包括True和False两种值(大小写需要严格遵循该写法,true、TRUE等都是错误写法)
    • python中 bool 是 int 的子类,且True == 1,False == 0,因此有:True + True =2 ; 10 * False = 0
    • 构造器:bool(),传入:0、None、空字符串、空数据结构(空列表、空字典、空集合)等都返回False,其他为True
    • Python中False, None, 0, 0.0, "", [], (), {}, set()以及各种空容器都视为假,其他对象通常被视为真;对象可以通过__bool__()自定义其真值

    float浮点数

    • 字面量:
      • 浮点数允许前导0,如:077.010和77.01都是合法的,表示同一值
      • 整数部分或小数部分可以为空,但不能同时为空,如:10.表示10.0;.001表示0.001
      • 可以使用e或E表示10的x次冥,如:1.0e3表示1000
    • 构造器:float()
      • 传入空参数时 float() 会创建0.0
      • 传入字符串时,字符串中只能包含正负号、数字、空白字符、e、分组符_,以及以下特殊值
      • float 支持三个特殊值:inf(正无穷,或用全写Infinity)、-inf(负无穷)、nan(not a number,无效数值,等同于JS的NaN)
      • 在判断一个float是否为nan时,应该使用math 模块中的 math.isinf(float),float('nan') == float("nan") 符号判断会返回 False

    复数

    • python使用j(或大写J)作为虚数单位而非 i,如:3+4.2j
    • j 前面的数字部分与浮点字面量的语法规则相同,如:3.14_15_93j也是合法表示

    NoneType

    None是 NoneType 类型唯一的实例,常用于表示没有值、缺省值或不存在的结果等,给 None 赋值是非法的并会引发 SyntaxError。

    序列

    序列是有限、有序的对象集,Python提供丰富的序列类型:

    • 容器序列:存放的是容器所包含对象的引用,它们能存放不同类型的数据:list (列表,可变序列)、tuple (元组,不可变序列)、collections.deque(collections模块提供的双向链表)
    • 扁平序列:只能存放一种类型的数据:range 对象、str(字符串)、bytes(二进制数据)、bytearray、memoryview、array.array
    • 只整理常用的类型

    序列的操作

    通用操作

    通用运算:

    • in/not in:判断某项是否存在于序列中,如:x in s,如果s中的某项等于x则结果为True,否则为 False,x not in s 反之
    • s + t:s 与 t 相拼接
      t1=(1,2,3) t2=('a','b','c') t1+t2 输出 (1, 2, 3, 'a', 'b', 'c') # 即便t1,t2是元组,内容无法修改,但它们可以通过该方式拼接出新的元组
    • s * n:相当于 s 与自身进行 n 次拼接
      t1 *3 输出(1, 2, 3, 1, 2, 3, 1, 2, 3)
    • 索引访问:以s[ i ]形式访问序列
      • 对于不可变序列,只能通过 s[i] 获得该元素,但不能修改;对于可变序列,可通过 s[i] = x 修改元素
      • 支持负数索引(从-1开始,因为-0 = 0,它们都指向序列的第一个元素),如对于字符串:word = 'python',word[-1] 为 'n'
    • len(s):返回序列长度
    • min(s):返回 s 的最小项
    • max(s):返回 s 的最大项
    • 切片(slice)操作:以s[i:j]方式获得/修改子序列,子序列不包含结束索引 j 指向的元素(左闭右开[i,j)形式),比如:word = 'python' 切片word[0:2] 输出 'py'。额外有:
      • 省略开始索引时,默认从 0 开始:word[:2] 输出为 'py'(不含2)
      • 省略结束索引时,默认到字符串的结尾:word[4:] 输出为 'on'(含4)
      • 负数索引类似:word[-2:] 输出 'on'(含-2)
      • s[:i] + s[i:]总是等于s:word[:4] + word[4:] 输出 'python'
      • 索引越界会报错:word[100]报错IndexError: string index out of range
      • 但切片会自动处理越界:word[4:42] 输出 'on'
      • 切片可以理解为如下排列形式,所切索引位于字符之间:
        loading
    • s[start:stop:step]:带步长的切片,表示序列s 从 start 到 stop 步长为 step 的切片,s[::-1]可以反转字符串,如:word = 'python';word[::-1]将输出'nohtyp'。步长切片的执行逻辑为:
      • 如果 step > 0,则默认 star = 0,stop = len(s),遍历取值
      • 如果 step < 0,则默认 star = len(s)-1,stop = -len(s)-1,遍历取值
      s=[0,1,2,3,4,5] s[:4:2] # [0, 2] s[:4:-1] # [5],start=5,stop=4(不包含)

    通用方法:

    • sequence.count(value):返回value在序列中出现的总次数
    • sequence.index(value[, start[, stop]]):返回value在sequence中首次出现所在的索引号,如果value不存在于sequence中则会引发ValueError。可以指定start 或 stop 参数来对该部分索引进行高效搜索

    可变序列类型支持

    可变序列类型支持的运算:

    • 通过索引、切片修改序列:如:s[i] = x(将第i项修改为x);s[i:j] = t(将 s 从 i 到 j 的切片替换为可迭代对象 t 的内容);s[i:j:k] = t
    • del 目标语句:删除元素:如:del list1(删除整个列表);del list[1](索引越界时报错);del list[2:4]等,注意del是一个语句,不是函数(print(del xx)是错误行为),没有返回值,语句del(lst[7])能运行是因为将(lst[7])视为了括号分组
    • 修改原序列:如:s += t 、 s *= n
      可变序列类型支持的方法
    • sequence.append(value) 添加value到序列末尾
    • sequence.clear()移除序列中的所有条目
    • sequence.copy()创建 sequence 的浅拷贝,等价于 sequence[:]
    • sequence.extend(iterable)使用 iterable 的内容扩展 sequence
    • sequence.insert(index, value)向位置index插入value,等价于切片操作:sequence[index:index] = [value]
    • sequence.pop(index=-1)从 sequence提取并移除位于index的条目并返回,不指定index时移除最后一个条目
    • sequence.remove(value)根据值从 sequence 中移除满足一个条目,如果该值有多个则只移除第一个
    • sequence.reverse()原地反转 sequence 的条目。此方法会在反转大尺寸序列时保持空间经济性,该方法返回值为 None

    不可变序列类型支持

    不可变序列类型特别支持的操作为:hash(),通过哈希可以将不可变序列映射为固定的键,方便存入字典等数据结构。可变类型由于内容可变,不适合通过哈希映射为键。

    list列表

    创建列表

    class list ( iterable ) 列表是可变序列,支持存储多种复合数据类型,列表可以用以下方式创建:

    • 使用方括号[]创建,如:squares = [1,2,'AA',3]
    • 使用类型的构造器: list( iterable ),如果 iterable已经是一个列表,将创建并返回其副本,如:list('abc') 返回 ['a', 'b', 'c']
    • 一些内置函数也会产生列表,比如:sorted()

    列表操作

    列表作为可变序列,支持 序列通用操作和可变序列支持的操作,以下是一些示例(来自Python官网的tutorial):

    • 支持索引、切片访问/修改元素:squares = [1, 2, 'AA', 3];squares[-2:]输出 ['AA',3]
    • 切片赋值可以修改列表大小,甚至清空列表:squares[:]=[] 此时squares将变为 []
    • 列表支持+号合并:squares + [11,22] 输出 [1, 2, 'AA', 3, 11, 22]
    • 列表元素是可被修改的(Mutable):squares[2]="BB"
    • 列表可用list.append()添加单个或一组元素:squares.append([0,0]) 结果为 [1, 2, 'AA', 3, [0, 0]]
    • 将列表赋值给一个变量时,该变量将引用列表,对变量的修改都将影响原有列表:
      list=[11,22,33] array = list # 引用赋值 array[1] = 'AA' list 将变为 [11,'AA',33]
    • 通过len()函数返回长度
    • 列表可以嵌套
      a = ['a', 'b', 'c'] n = [1, 2, 3] x = [a, n] # x 将变为 [['a', 'b', 'c'], [1, 2, 3]] # x[0]将输出['a', 'b', 'c'] # x[0][1]将输出 'b'

    sort方法

    list.sort(key=None, reverse=False)根据指定的key和reverse值进行排序,这是list额外提供的方法

    • 该方法是原地排序(in-place),直接修改原列表,返回值为 None;功能与之相似的有内置函数 sorted(),sorted()会返回新列表,不改变原列表
    • 排序时会使用<符号在各项间进行比较,以决定这些元素的先后顺序,如果任何比较操作失败,整个排序操作将失败。因此如果list中包含多个不同类型的元素(如:[1, 2, 'AA', 3]),直接执行list.sort()将抛出TypeError,因为不允许 int 和 str 比较大小,解决方法参考下文示例
    • key是一个可选项,用于指定一个函数,排序时按照该函数的返回值进行比较,默认值为 None,常用的值有str.lower(忽略大小写)、len(按长度排序)、abs(按绝对值排序)或是自定义的 lambda 函数
    • reverse是一个可选项,用于指定是否反转排序,默认值为 False,会升序排列,可选值还有 True
    • Python还提供sorted()函数,该函数返回一个新列表,而不修改原列表,如:sorted(list2)
    1. 默认情况下,sort会进行升序排序 nums = [3, 1, 4, 1, 5, 9, 2, 6] nums.sort() #nums变为[1, 1, 2, 3, 4, 5, 6, 9] nums.sort(reverse=True) #nums变为[9, 6, 5, 4, 3, 2, 1, 1] 2. key 参数有以下用法 # 按字符串长度排序 words = ["apple", "banana", "kiwi", "cherry"] words.sort(key=len) # ['kiwi', 'apple', 'banana', 'cherry'] # 按绝对值排序 nums = [-5, 3, -1, 4, -2] nums.sort(key=abs) # [-1, -2, 3, 4, -5] # 忽略大小写排序 names = ["Bob", "alice", "Charlie", "david"] names.sort(key=str.lower) # ['alice', 'Bob', 'Charlie', 'david'] 3. 使用 lambda 表达式 # 按元组第二个元素排序 data = [(1, 3), (2, 1), (3, 2)] data.sort(key=lambda x: x[1]) # [(2, 1), (3, 2), (1, 3)] # 按字典某个字段排序 students = [ {"name": "Tom", "age": 20}, {"name": "Amy", "age": 18}, {"name": "Bob", "age": 22}, ] students.sort(key=lambda s: s["age"]) # Amy(18), Tom(20), Bob(22) 4. 当list中是混合类型的元素时,需要通过key参数调整比较方式 lst = [1, 2, 'AA', 3] lst.sort() #报错TypeError: '<' not supported between instances of 'str' and 'int' # 将每个元素转成字符串再比较 lst.sort(key=str) #相当于按字典顺序比较['1','2','AA','3'],lst会排序为[1, 2, 3, 'AA'] # 先排序所有 int 再排序 str lst.sort(key=lambda x: (type(x).__name__, x)) #[1, 2, 3, 'AA'] lambda表达式相当于 def key_func(x): return (type(x).__name__, x) 它会返回一个元组(type(x).__name__, x),将上述元素转换为: [('int', 1),('int', 2),('str', 'AA'),('int', 3)] 将首先按元组的第一个元素比较,即所有的int将先排序,再排序str

    tuple元组

    创建元组

    class tuple( iterable ) 元组属于不可变序列,一旦初始化就不能修改,可通过以下方式创建:

    • 使用圆括号( )创建,如:创建空元组(),或创建有多个项的元组(a,b,c)
    • 但真正决定生成元组的其实是逗号而不是圆括号,圆括号只是可选的(创建空元组,函数f((1,2,3))需要传入一个元组时除外)
    • 因此定义一个只有1个元素的tuple时需要添加后缀逗号,如:a, 或 (a,);这是因为圆括号还用于运算表达式,如:result=(1+2)*1,因此如果是 tuple1=(1),则定义的是整数1,type(tuple1)返回的类型是int
    • 使用内置的构造器tuple( iterable )创建元组:tuple('abc')将返回('a', 'b', 'c') 而 tuple([1, 2, 3]) 返回(1, 2, 3),不提供参数将创建空元组

    元组操作

    元组属于不可变序列,但如果其元素是对一个对象的引用,该对象的值是仍然可改变的

    t = ('a', 'b', ['A', 'B']) t[2][0] = 'X' t[2][1] = 'Y' print(t) #('a', 'b', ['X', 'Y']),元组t[2]依旧指向一个list对象,其指针指向对象并没有变,只是list内部值改变了

    range对象

    range (start,stop,step)该类型表示不可变的数字序列,常用于在 for 循环中循环指定的次数

    • start,stop,step都必须是整数,它不像shell语言中的seq一样支持小数步长增长
    • 如果省略 step 参数,则默认为 1。如果省略 start 参数,则默认为 0
    • 执行时从 start 开始,每次加 step,直到达到或超过 stop 就停止,但永远不包含 stop 本身(左闭右开)
    • 负数的step会降序:list(range(10,5,-1)) 生成 [10, 9, 8, 7, 6]
    • range 对象只保存start, stop 和 step 值,因此无论最终产生的序列有多大,它都占用固定数量的内存,然后通过r[i] = start + step*i生成内容,因此它很适合用于运行时生成大量列表等

    str字符串

    Python中,字符串(string)将被作为文本序列进行处理,在Python 3中,字符串是以Unicode编码的,因此可以表示各种语言的文本。作为不可变序列,字符串支持序列的通用操作,还具有不可变序列所共有的特性。在此基础上,字符串类型还提供了大量针对文本处理的专用操作

    创建字符串

    • 使用构造器str( object ),如:str(123)返回'123';str(b'hello', encoding='utf-8')返回#'hello'(或b'hello'.decode());str([1, 2])返回'[1, 2]',如果需要的是'1,2'则需要",".join(str(x) for x in nums),构造器只返回 object 的 str 表示
    • 字符串字面量声明可以使用"双引号"或'单引号'包裹,它们完全一样
    • 使用三重引号"""三重双引号"""或'''三重单引号'''可以跨行输入文本,并且行结束符会被包含在字符串内(print输出时会保留文本的样式),如果不希望保留行结束符,可以在行尾使用延续字符\
    • 如果文本本身包含单双引号,可用\转义,如:'doesn\'t',或者外部使用另一种引号:"doesn't"
    • Python shell中,直接输出字符串字面量,其中的转义字符(如:\n)不会被解析,通过print()函数输出则会解析转义字符
      >>> s = "AA\nBB" >>> s # 不用 print(),特殊字符将包括在字符串中不转义 AA\nBB >>> print(s) # \n会被转义 AA BB

    字符串前缀

    Python 中字符串字面量允许带有不同的前缀(前缀不区分大小写):

    • r(raw,原始字符串):转义序列不再会被转义,而是会原样输出,常用于正则表达式、文件路径等。如:s2 = r"C:\new\test"(避免\n被转义),该前缀可以与f、t、b前缀组合使用,不区分顺序(rf和fr一致)
    • f(formatted,格式化字符串f-string):用于在字符串中直接嵌入表达式,如:print(f"{name} is {10+8} years old"),通过{ }引用变量/执行语句,如果要输出{}本身,只需要两个大括号嵌套即可
    • t(template,模板字符串t-string):与f类似,但可以防止SQL 注入、HTML 转义等
    • b(bytes字节串字面量):用于表示 bytes类型 的字节序列,而不是字符序列(str类型),前者常用于网络传输和文件存储。字节串字面量中的直接字符只能使用ASCII 字符,其他字符必须使用编码后的转义序列来表示。如:s = b"hello" ,如果需要将包含中文等非 ASCII 字符的 str 转换为 bytes,可以使用encode(),如:s = "你好".encode("utf-8"),print(s) # b'\xe4\xbd\xa0\xe5\xa5\xbd'
    • u: 无效果,为兼容Python2而保留,不能与r同时出现

    字符串拼接

    • 多个相邻的字符串字面量会被自动合并,如:'py''thon'会被合并为'python',这允许跨行输入不需要延续字符或三重引号。该功能不能用于变量或表达式拼接,比如str1="AA",不允许:str1"new content"
      >>> text = ('Put several strings within parentheses ' ... 'to have them joined together.') >>> text #字符串会被拼接 'Put several strings within parentheses to have them joined together.'
    • 字符串也可以用+号拼接,且允许变量和表达式拼接,比如:3 * 'un' + 'ium',或者str1 + "new content"

    常用字符串操作

    以下是str对象中常用的方法,这些方法时应该通过str.形式在对象身上调用,字符串是不可变序列,因此它们都不会对原串进行修改,一般都是返回一个新的字符串
    查找

    • 检查某个字符串是否属于另一个串的一部分,应该使用in操作符,而不是以下方法
    • find('子串'[,start[,end]] )获得子串 sub 出现时的最小索引,可以指定 start和end 指定查找范围(只有单个值将指定的是start),如果未找到返回-1。如:'spam, spam, spam'.find('sp', 5) 返回6,rfind()用法类似,它返回的该子串出现时的最高索引(倒查)
    • index('子串'[,start[,end]]):类似于find(),但找不到子串时抛出错误,rindex()类似于rfind(),同样在找不到子串时抛出错误
    • count('子串'[, start[, end]]):返回子串 sub 在 [start, end] 范围内出现的次数
    • startswith('前缀'[, start[, end]]):如果字符串以指定前缀开头则返回True,前缀可以是多个想匹配元素组成的元组,如:'a tuple '.startswith(('at', 'a')),同样可以指定查找范围
    • endswith('后缀'[, start[, end]]):如果字符串以指定后缀结束则返回True,同样支持通过元组提供多个匹配项,如:'a tuple of suffixes'.endswith(('at', 'es'))

    分割与拼接

    • join(iterable):返回一个字符串,它是在可迭代对象iterable(列表,元组、集合、生成器、字典、文件对象)中的元素之间插入当前字符串拼接而成的。如:"==".join(['1','2','3']) 拼接出 '1==2==3',该方法的性能比+号拼接性能更好。但注意iterable中的元素必须全部是字符串,如果不是则需要提前处理

      nums = [1, 2, 3] #需要将元素处理为字符串 # 转为字符串'1,2,3' ",".join(str(x) for x in nums) #通过 生成器 ",".join([str(x) for x in nums]) #通过 列表推导式
    • split(sep=None, maxsplit=-1):分割字符串,返回一个列表,如:"a--b--c".split("--",3) #返回 ['a', 'b', 'c']

      • sep:可选,指定分隔符,默认为 None,按照空白字符(空格、\t、\n、\r、\f、\v)分割
      • maxsplit:可选,指定最大分割次数,默认为-1无限制,如果指定maxsplit,在达到最大分割次数后剩余部分会作为最后一个元素
    • splitlines(keepends=False):不同OS换行符不同,该方法能识别所有 Unicode 行边界(\n、\r、\r\n、\v、\f、\u2028 等),常用于跨平台处理文本行,它返回一个列表,执行时如果为splitlines(True)则会保留行尾的换行符,如:

      content = "a=1\nb=2\nc=3" config = {} for line in content.splitlines(): if "=" in line: k, v = line.split("=", 1) config[k] = v print(config) # {'a': '1', 'b': '2', 'c': '3'}

    替换

    • replace('旧串', '新串'[,count=-1]):替换字符串中的指定的旧字符串为新字符串,并返回一个字符串的副本,指定count只替换前count次,默认为-1替换所有旧字符串
    • strip(chars=None):返回原字符串移除前导和末尾字符后的副本,如果不指定chars,则默认移除字符串左右两侧的空白字符。chars指定的是一个字符集合,如:'www.example.com'.strip('cmowz.')后变为'example',由此引申出:
      • lstrip(chars=None):只移除字符串左侧的指定字符
      • rstrip(chars=None):只移除字符串右侧的指定字符
    • removeprefix('前缀子串'):如果字符串以指定的前缀开头,则返回移除该前缀后的字符串;如果并不以该前缀开头,则返回原字符串的副本,如:'TestHook'.removeprefix('Test') 返回 'Hook'
    • removesuffix('后缀子串'):如果字符串以指定的后缀结尾且不为空,则返回移除该后缀后的字符串;否则则返回原字符串的副本
    • translate(table):用于将某些字符转换为另外的字符,如:将'0123456789'替换为'零一二三四五六七八九'中对应的字符,但该方法要求传入的是一个table,它通常由str.maketrans()生成
    • str.maketrans():这是一个静态方法,用于返回一个给translate()方法使用的转换对照表(table),主要有以下三种用法:
      • 传入字典:t1 = str.maketrans({"a": "A", "b": "Bob","c":None}) "abc".translate(t1) 以实现将a替换为A,b替换为Bob,c替换为空(删除);因此字典中的值可以是一个字符、一个字符串、None(实现删除)
      • 传入两个等长字符串,一一对应替换:t2 = str.maketrans("0123456789", "零一二三四五六七八九") print("2024".translate(t2)) #输出二零二四
      • 传入三个字符串,一替换二,删除三:如:t3 = str.maketrans("abc", "xyz", "123") print("a1b2c3".translate(t3)) #输出xyz且1、2、3已被删除
        大小写转换
    • lower():将字符串转换为小写,返回转换后的字符串
    • upper():将字符串转换为大写,返回转换后的字符串
    • capitalize():首个字符大写,其余为小写,返回转换后的字符串
    • title():返回原字符串的标题版本,其中每个单词第一个字母为大写,其余字母为小写,如:'hello world'.title() 转换为 'Hello World'
    • swapcase():将原字符串中的小写转为小写,小写转为大写

    字符串类型判断:判断整个字符串是否为全字母/数字等,是则返回True,否则返回False

    • isalpha():判断是否全为字母(Unicode字母、中文也算字母),如果包含空格、数字等返回False
    • isdecimal():判断是否只包含数字(0-9以及少数Unicode十进制数字),带有小数点、正负号、指数、罗马数字(如:IV)都将返回False
    • isdigit():判断是否全为数字,指数等上标、下标也视为digit
    • isnumeric():判断是否全为数值字符,上标、下标,罗马数字等字符也视为True
    • isalnum():是否全是字母或数字,数字包含numeric,因此只有在带有空格、各类符号时才会False
    • isidentifier():是否是合法 Python 标识符(变量名)
    • islower():是否所有字母都小写,带有的其他符号不影响判断,但如果一个字母没有会返回False
    • isupper():是否都是大写,规则同上
    • istitle():是否满足标题格式(每词首字母大写),规则同上
    • isspace():是否全是空白字符。
    • isprintable():是否全可打印,不包含控制字符

    格式化

    Python中字符串格式化方法很丰富:

    • str.center(width,'fillchar'):字符串内容居中,左右两侧填充fillchar指定的字符,返回长度为 width 的字符串。width和fillchar参数都是可选项,默认填充空格,如果指定的width小于len(原字符串),会直接返回原字符串副本。如:'Python'.center(10, '-') 输出 '--Python--'
    • str.ljust(width,'fillchar'):字符串左对齐,返回 width 长度的字符串,右侧用指定的fillchar字符填充,参数用法同上,如:'Python'.ljust(10, '.') 输出 'Python....'
    • str.ljust(width,'fillchar'):字符串右对齐,右侧填充fillchar字符,返回 width 长度的字符串,用法同上
    format方法

    str.format()是Python进行字符串格式化的一个非常强大的方法,其语法为:

    "字符串".format(*args, **kwargs)

    • 允许传入 *args:位置参数;**kwargs:关键字参数,且允许字符串中预留 {} 作为占位符
    • 位置参数:format允许按指定的索引填充字符串中预留的位置参数,如果 {} 数量与参数不匹配会报错
      "{0} {1}".format("Hello", "World") # 'Hello World' "{1} {0}".format("Hello", "World") # 'World Hello'
    • 关键字参数:可按关键字填充参数,而无需管参数索引顺序:
      "{name} is {age}".format(name="Tom", age=18) # 'Tom is 18' "{age} {name}".format(name="Tom", age=18) # '18 Tom'
    • 位置参数和关键字参数可以混用,但位置参数必须在前面:
      "{a} {}".format("x", a=1) # 合法 "{} {a}".format(a=1, "x") #非法
    • 可以访问对象属性或元素
      t1={"name":"Tom","lang":"Python"} print("{0[name]} uses {0[lang]}".format(t1)) # Tom uses Python
    • 占位符中允许使用{[字段名]:[格式说明符]}形式进行格式控制:
    完整格式为 {[参数名]:[填充][对齐][符号][#][0][宽度][,][.精度][类型]} 1. 指定对齐与填充 "{:>10}".format("hi") # ' hi' 右对齐 "{:<10}".format("hi") # 'hi ' 左对齐 "{:^10}".format("hi") # ' hi ' 居中 "{:*^10}".format("hi") # '****hi****' 用 * 填充 2.数字格式化 "{:+d}".format(42) # '+42' 显示符号 "{: d}".format(42) # ' 42' 正数前加空格 "{:05d}".format(42) # '00042' 补零 "{:,}".format(1234567) # '1,234,567' 千分位 "{:.2f}".format(3.14159) # '3.14' 保留两位小数 "{:.2%}".format(0.1234) # '12.34%' 百分比 "{:.3e}".format(12345.6) # '1.235e+04' 科学计数 "{:b}".format(10) # '1010' 二进制 "{:o}".format(10) # '12' 八进制 "{:x}".format(255) # 'ff' 十六进制 "{:#x}".format(255) # '0xff' 带前缀 3. 复用参数与嵌套字段 如:以变量形式提供输出宽度 "{:{width}}".format("hi", width=6) # 'hi '
    f-string

    格式化字符串f-string(Python 3.6 引入),使用f或F前缀,用于在字符串中直接嵌入表达式,它在运行时求值,通常比 format() 更快

    1. 在字符串中访问、操作变量 name = "Tom" age = 18 f"{name} is {age}" # 'Tom is 18' f"{name} is {age + 1}" # 'Tom is 19' 可放任意表达式 f"{name.upper()}" # 'TOM' 可调用方法 f"{'yes' if age >= 18 else 'no'}" # 'yes' 2. 可以使用与 format 相同的格式化语法,如: x = 3.14159 f"{x:.2f}" # '3.14' f"{x:>10.2f}" # ' 3.14' 3.支持多行f-string msg = ( f"Name: {name}\n" f"Age: {age}" )

    t-string

    模板字符串t-string是 Python 3.14 新引入的语法,用t或T前缀,它返回一个 Template 对象而不是普通字符串。Template 对象会保留"静态文本 + 插值"的结构,开发者需要手动拼接这些字符串,适用于防止SQL 注入等安全场景(如 SQL 拼接、HTML 生成、日志脱敏)

    t-string返回的是一个Template 对象 name = "Tom" t1=t"hello,{name}" print(t1) # 输出 Template( strings=('hello,', ''), interpolations=(Interpolation('Tom', 'name', None, ''),)) Template对象包含两部分: t.strings:静态文本片段 t.interpolations:插值对象 开发者需要手动拼接上述属性中的值

    编码

    字符与码点

    Unicode是一种统一的字符集标准,用于为世界上的各种字符建立统一的编号体系,解决不同国家和语言使用不同字符编码所造成的兼容问题。Unicode 为每个字符分配了一个唯一的码点(code point)(可视为一个整数,占用21位),通常写成U+十六进制数形式 ,如:'A' → U+0041;'中' → U+4E2D。Python 3 使用 Unicode 表示文本,str管理的是 Unicode 码点序列,可以使用以下语句在字符与码点之间转换:

    • ord('字符'):获取字符对应的 Unicode 码点,返回 int。如:ord('中') 输出 20013
    • chr(码点):根据 Unicode 码点得到对应的字符,返回 str。如:chr(65) 输出 'A'
    字符编码

    Unicode 为每个字符都提供了独一无二的编号,但网络传输和文件存储并不直接传输/存储完整的 21 位 Unicode 码点,而是通过编码(encoding)将unicode码点转换为字节序列,常见的编码方式有ASCII、UTF-8、UTF-16 等,以常用的 UTF-8 为例。

    UTF-8 是变长编码,其特点为:

    • 首字节的前缀决定后续跟几个字节(首字节开头有几个 1,就表示总共占几个字节)
    • 10 开头是续字节,需要和前面的字节组合使用
    • 这样即使从中间某个字节开始读,也能通过前缀识别这是不是字符边界,方便检验
    码点范围 二进制表示 字节数 内容
    U+0000 ~ U+007F 0xxxxxxx 1 ASCII:英文、数字、标点、控制符
    U+0080 ~ U+07FF 110xxxxx 10xxxxxx 2 阿拉伯字母、希腊字母等
    U+0800 ~ U+FFFF 1110xxxx 10xxxxxx 10xxxxxx 3 中文、日语、韩语等
    U+10000 ~ U+10FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 4 生僻汉字、emoji、音乐符号等

    UTF-8编码带来的优势:

    • 不需要每个字符都占用21位(为字节对齐需要拓展到24位),能节省网络传输、文件存储所需资源
    • 完美兼容ASCII,兼容早期使用ASCII的设备
    编码/解码

    Python使用以下方法实现从Unicode 字符到字节数据的编码/解码:

    • str.encode(encoding="utf-8", errors="strict"):将unicode字符编码为字节数据,该方法返回一个bytes 对象,如:print("你好".encode()) 输出 b'\xe4\xbd\xa0\xe5\xa5\xbd'
      • encoding指定编码方式,默认为"utf-8"
      • errors指定如何处理编码错误,允许的值有:
        • 'ignore':忽略无法编码的字符
        • 'replace':用?替换无法编码的字符,输出形式类似于b'??abc'
        • 'xmlcharrefreplace':用 XML 字符引用替换
        • 'backslashreplace':用 \xNN 转义替换无法编码的字符,输出形式类似于 b'\\u4f60\\u597dabc'
        • 任何通过 codecs.register_error() 注册的其他名称
    • bytes.decode(encoding='utf-8', errors='strict'):返回解码为 str 的字节串,encoding和errors参数用法同上

    其他字符表示

    • \ooo可以表示一个八进制字符,如:'\120'表示'P'
    • \xhh(必须两位)可以表示一个十六进制字符,如:'\x50'表示'P'
    • \N{name} 表示具有给定 name 的Unicode字符,如:'\N{SNAKE}'表示'🐍'
    • \uxxxx(\u需要4位)和\Uxxxxxxxx(\U需要8位)表示具有给定十六进制值的Unicode字符

    bytes

    bytes是一种不可变的字节序列类型,序列中的每个元素都是 0~255 的整数(一个字节),用于表示二进制数据,包括:

    • 文本经过某种编码后的字节(UTF-8等)
    • 图片、音频、视频的原始数据
    • 网络协议数据包
    • 加密/压缩后的数据
    • 序列化后的对象

    创建bytes

    • 通过构造器bytes( source )创建
      • 可传入一个整数n,创建一个 n 字节值全 0 的字节串:如:bytes(5) 创建出b'\x00\x00\x00\x00\x00';如果不传入参数,则创建一个空字节串,长度为0,如:b1 = bytes(),b1指向一个bytes对象,该对象中存储的值为b''
      • 传入一个可迭代对象,这些对象的每个元素必须是0-255的整数:如:bytes([65, 66, 67])值为b'ABC';bytes(range(3))值为b'\x00\x01\x02'
      • 传入字符串,必须指定编码方式:如:bytes('abc')报错without an encoding,必须bytes('abc', 'utf-8');bytes('abc', 'utf-8', 'strict'),关于编码的参数参考 str编码
      • 实际上,构造器通过尝试调用对象的 bytes 方法,或者走 buffer 协议来创建bytes
    • 通过字面量:以b'xxx'形式
      • 这里字符串中的直接字符只接收ASCII字符,如:b"hello"是允许的,b'你好'是非法的
      • 非ASCII码需要经过编码,以转义序列方式给出,如:b'\xe4\xbd\xa0\xe5\xa5\xbd'(代表utf-8下的你好)
    • 其他一些方式也会返回/创建bytes,如:以二进制模式读文件,with open('a.bin', 'rb') as f: data = f.read()将返回bytes

    bytes与str

    字符串可以通过字面量(ASCII字符)或字符串编码(非ASCII字符,通过 str.encode()方法 )形式快速转为bytes,方便网络传输、文件存储等,参考 str编码/解码

    1. 通过索引访问bytes时,返回的是其对应字节的数据 对于ASCII,由于一个字符占用一个字节,这刚好返回的是对应字符的 int 类型表示 b1 = b'abcd' print(b1[0]) # 97 print(ord('a')) # 97 对于中文,一个中文在utf-8编码下,占用3字节,单个字节的数据是没意义的,需要对应字节数的数据 b2 = "你好".encode() print(b2) # b'\xe4\xbd\xa0\xe5\xa5\xbd' print(b2[0:3].decode()) #'你' print(' '.join(str(x) for x in b2)) #转为十进制'228 189 160 229 165 189'

    bytearray

    bytes 是不可变字节序列,不支持对原数据的修改,由此Python还提供了 bytearray,它是可变字节序列,属性与接口与 bytes 很相近,但它支持原地修改,支持可变序列的一系列操作

    创建bytearray

    bytearray中的每个元素也是 0~255 的整数,构造方法与 bytes 几乎相同:bytearray( source )

    • 可传入整数、可迭代对象、字符串,如:bytearray([65, 66, 67])输出bytearray(b'ABC')
    • 可以直接将 bytes 改造成 bytearray:bytearray(b'abc')
    bytearray提供的便捷之处就在于就是可以修改字节串了 ba = bytearray(b'abc') ba.append(100) # 追加一个字节,bytearray(b'abcd') ba.extend(b'ef') # 追加多个字节,bytearray(b'abcdef') ba.insert(0, 65) # 在位置 0 插入一个int,打印后为bytearray(b'Aabcdef') ba.remove(65) # 根据值删除字节 ba.pop(0) # 根据位置弹出字节 ba.reverse() # 原地反转

    memoryview

    memoryview是 Python 提供的二进制数据视图类型,用于让程序直接访问处理其他对象所提供的底层内存缓冲区,而不必复制其中的数据。它实现的是对支持缓冲区协议(Buffer Protocol)对象的"零拷贝"视图,并暴露访问接口,因此创建 memoryview 通常不会复制原对象中的数据。它常用于:

    • 零拷贝(Zero-copy)处理大数据:在处理大文件、网络数据包、图像/音频缓冲区时,不会像切片 bytes、bytearray 一样创建新对象并复制数据,能显著节省内存和 CPU
    • 高效解析网络包、文件头、二进制格式

    创建memoryview

    使用构造器memoryview( )创建,创建时如果底层对象是只读的,例如 bytes,则创建出来的 memoryview 也是只读的,因为它们本质上是同一块缓冲区

    mv = memoryview(b'abc') # 从 bytes mv = memoryview(bytearray(10)) # 从 bytearray mv = memoryview(array.array('i', [1,2,3]))

    属性

    • mv.obj:底层原对象
    • mv.nbytes:总字节数
    • mv.itemsize:单个元素字节大小
    • mv.ndim:维度数
    • mv.shape:各维度大小(元组)
    • mv.strides:各维度步长(元组)
    • mv.format:元素格式(如 'B'、'i')
    • mv.readonly:是否只读(bool)
    • mv.contiguous:是否连续内存
    • mv.c_contiguous / mv.f_contiguous:C / Fortran 连续

    操作

    • 支持索引、切片:且如果数据不是readonly,可以通过该方式赋值,如:mv = memoryview(b'hello');mv[0] # 104
    • mv.release():释放缓冲区
    • mv.toreadonly()返回只读视图
    • mv.cast():指定数据的解释方式,具体参考文档
      将数据复制独立出来
    • mv.tobytes():将数据复制为bytes,如:data = bytearray(b'abcdef');view = memoryview(data);b = view.tobytes(),此时 b 是独立的 bytes 对象,与原缓冲区不再共享数据
    • mv.tolist()::将数据复制为list
    高效切片处理大文件,而不用复制内存区域 with open('big.bin', 'rb') as f: data = f.read() mv = memoryview(data) header = mv[:16] body = mv[16:]

    集合

    集合(set)是一种用于存放不重复、无序元素的容器类型。常用于去除重复元素、判断元素是否存在、进行并集、交集、差集、对称差集等运算。集合中的元素必须是可哈希(hashable)的,因此不能直接包含 list、dict、set(嵌套另一个集合)等不可哈希对象。Python 提供两种集合类型:

    • set:可变集合,如:{1,2,3}
    • frozenset:不可变集合,如:frozenset({1, 2, 3})

    特点

    集合有以下鲜明的特点,并决定了它的操作:

    • 元素无序:集合不按照元素加入的顺序保存元素,因此操作不能依赖元素的排列顺序,由此不支持索引、切片操作。要在保证元素出现顺序的情况下去重,参考 字典的dict.fromkeys( iterable )方法
    • 元素不重复:集合中的同一个元素只能出现一次,因此常用于去重:list(set([1, 2, 2, 3, 3]))去重后为 [1, 2, 3]
    • 元素必须可哈希:集合内部元素必须是可哈希对象,因此集合元素可以是int、str、tuple、frozenset等本身不可变的类型,如:{1, "abc", (1, 2)},但不能是list、普通set、dict,如:不能是 {[1, 2]}、{"a": 1}、{{1, 2}}

    集合的底层实现

    集合的无序、元素不重复、元素需要可哈希来源于它的底层实现,这里对比list进行介绍

    对于 list 等可以通过索引、切片操作元素的数据类型,它们的“序号”是数据模型的一部分,如: a = ['a', 'b', 10, 'd'] 底层 CPython 中,list 本质上是一个连续的指针数组,数组中的每个指针指向一个 python 对象 a[0] → str类型对象 'a' a[1] → str类型对象 'b' a[2] → int类型对象 10 a[3] → str类型对象 'd' 可以根据索引直接定位到第三个指针,实现索引、切片访问功能,由此带来的特点: 1. 当执行 a.insert(1, 'x'),为了维持顺序,需要依次移动后面的指针,效率低 2. 执行 in 操作检查某个元素是否已经存在于列表,需要遍历比较值,效率低 3. 元素顺序相对固定,内存利用率高
    set 的核心目标是为了判断快速判断某个元素是否存在,因此它利用哈希表组织元素,如: s = {'apple', 'banana', 'cat'} 会生成哈希表槽位: 哈希表槽位: [0] empty [1] banana [2] empty [3] cat [4] empty [5] apple [6] empty 哈希表本质上是一个稀疏数组,数组中总是有空白元素,CPython总是会设法保证大约有三分之一的表元是空的,当快要达到这个阈值时,原有的哈希表会被复制到一个更大的空间中,即进行扩容 通过 in 操作检查一个元素是否存在于集合中时,Cpython会执行 hash(element) 计算出其哈希值,将该值的最低几位数字作为偏移量,在哈希表中找到表元,如果该表元为 empty ,则说明不存在于集合中 插入一个元素时,会通过 hash(element) 计算它应该放在哪个哈希表位置,Python会按照哈希表拥挤程度决定是否需要重新分配内存进行扩容 由此带来特点是: 1. in 操作很快:查询某元素是否已经存在于集合,只需要计算出该元素的哈希,并在表中检查哈希表项是否为空即可 2. 元素必须是可哈希的 3. 内存开销巨大:由于使用散列表,而散列表又必须是稀疏的,因此空间利用率低下,本质是空间换时间,存储巨大数量的记录选择元组、列表更好 4. 添加新元素可能导致扩容,哈希表变大,导致已有元素顺序改变

    集合操作

    • in/not in:判断某项是否存在于集合中,如:x in s,如果s中的某项等于x则结果为True,否则为 False,x not in s 反之
    • len(s):返回集合中的元素数量
    • 支持迭代:但迭代顺序不应作为程序逻辑依据,两次执行相同代码可能因为集合扩容导致元素顺序变更,程序有不同结果
      判断集合关系
    • a <= b:a 是 b 的子集则返回True,等价于 a.issubset(b)
    • a < b:a 是 b 的真子集则返回True
    • a >= b:a 是 b 的超集则返回True,等价于a.issuperset(b)
    • a > b:a 是 b 的真超集则返回True
    • a == b:检查两个集合元素是否相同,结果只取决于元素是否相同,与元素排列无关,a != b 类似
    • a.isdisjoint(b):若两个集合并无交集,则返回True
      以下操作会创建新集合
    • 并集 a | b 或 a.union(b):两个集合中所有元素组成的新集合
    • 交集 a & b 或 a.intersection(b):两个集合共同拥有的元素组成一个集合
    • 差集a - b 或 a.difference(b):出现在第一个集合、但不出现在第二个集合中的元素,a - b 和 b - a 结果通常不一样
    • 对称差集a ^ b 或 a.symmetric_difference(b):只出现在其中一个集合、但不同时出现在两个集合中的元素,如:{1, 2, 3} ^ {2, 3, 4} = {1, 4}

    可变集合 set

    创建 set

    • 使用构造器set( iterable ),如:set([1,2,3]),当然元素不能是可变的,如:set([1,2,[3]])中[3]是list,非法元素
    • 集合字面量使用{ }包裹,如:s={1,2,3},空集合必须用构造器set()构造,{ }创建的是空字典

    可变集合的操作

    set 是可变类型,因此除了集合的公共运算外,还提供修改自身的方法

    • s.add(x):添加元素x,如果x已经存在,不会产生重复元素
    • s.remove(x):删除指定元素,如果元素不存在,会抛出 KeyError
    • s.discard(x):删除指定元素,不存在也不会报错
    • s.pop():随机弹出一个元素,由于集合无序,不应该假定 pop() 返回哪个元素
      集合还支持以下原地修改
    • 并集a |= b 或 a.update(b):原地修改a为二者并集
    • 交集a &= b 或 a.intersection_update(b):原地修改a为二者交集
    • 差集a -= b 或 a.difference_update(b):原地修改a为二者差集
    • 对称差集a ^= b 或 a.symmetric_difference_update(b):原地修改a为二者对称差集

    冻结集合frozenset

    frozenset 是不可变集合类型,它与 set 一样保存不重复元素,但创建后不能增加、删除或修改元素。

    由于 set 是可变的,因此它不能作为 set 的元素、dict的键,但 frozenset 可以,因此frozenset的最大作用就是替代 set 完成上述任务。

    创建frozenset

    使用构造器frozenset(iterable),如:从set接收 frozenset({1, 2, 3}) 或创建空的冻结集合frozenset()

    映射类型

    映射(mapping)是一类通过可哈希对象作为键(key)映射到任意对象作为值(value)的数据类型。映射类型是可变对象,可以根据键查找、添加、修改和删除对应的值。Python 标准库目前提供的标准映射类型是字典(dict),此外 collections 模块还提供了 dict 的变种,如 defaultdict 和 OrderedDict,它们在 dict 的基础上针对特定使用场景提供了不同的行为

    字典dict

    字典(dict)是一种可变的映射(mapping)类型,用于存储键值对(key-value pair)数据,在有的语言中被称为map,能通过键可以快速找到对应的值,具有极快的查找速度。字典:user = { "name": "Tom", "age": 20, "city": "Beijing" }

    字典的特点

    • 可变(mutable):可以增、删、改键值对
    • 保存键值对(key-value pair):数据以 key: value 形式成对出现
    • 通过键访问值,而不是通过位置访问
    • 键必须是可哈希对象且键不能重复,支持作为键的类型有如:1、3.14、"abc"、(1, 2),不可作为键的类型有:列表 [1, 2]、集合{1, 2}、字典{"a": 1}
    • 如果向字典中加入已经存在的键,不会产生新的元素,而是修改该键对应的值
    • 值可以重复,也可以是任意类型
    • 查询高效:基于哈希表实现,查找平均时间复杂度 O(1)
    • 有序性:Python 3.7+以后开始,字典保持插入顺序

    字典的底层实现

    类似于集合set,字典在Python中也是通过散列表实现的

    • 字典底层使用哈希表保存键值对,其基本实现思想与集合(set)类似。插入或查找元素时,Python 首先对键调用 hash() 计算哈希值,再根据哈希值确定其在哈希表中的候选位置,因此字典根据键进行查找、插入和删除的平均时间复杂度通常为 O(1)
    • 根据键查找值时,Python 首先调用 hash(search_key) 计算键的哈希值,并取哈希值的最低几位作为偏移量,在哈希表中定位对应的表元(slot)
      • 如果表元为空,说明字典中不存在该键,返回异常或空
      • 如果表元不为空,则比较其中保存的 key 与 search_key 是否相等。如果相等,则找到对应的值
      • 如果两者不相等,说明发生了哈希冲突,算法需要从哈希值中另取几位进行处理,利用新得到的偏移值查找表元,并重复上述步骤,直到找到目标键或确定该键不存在(这种冲突很少,百万个元素的dic,每次搜索平均下来才有一两次冲突)
    • 插入新的键值对时,Python 会根据哈希表的拥挤程度决定是否扩容。扩容后需要重新组织表中的元素,使哈希表保持较低的装载程度,从而减少哈希冲突和探测次数,维持字典查找、插入和删除操作接近 O(1) 的平均时间复杂度

    创建字典

    • 通过构造器dict( ),如:d = dict(name="Tom", age=20);d = dict([("a", 1), ("b", 2)])
    • 使用{ }创建字面量,如:空字典d = {}
    • 字典推导式,如:d = {x: x * x for x in range(10) if x % 2 == 0}
    • 通过zip()将两个序列组合成键和值,再转换为字典:keys = ["name", "age"] values = ["Tom", 20] d = dict(zip(keys, values))

    字典操作

    • 以下方法中,d 指代已经声明好的字典对象
    • in/not in:判断键是否存在于字典,判断值是否存在可以使用:"值" in d.values()
    • len(d):返回的是字典中键值对的数量
    • d["键"]:访问该键的值,如果键不存在,会抛出 KeyError
    • d.get("键"[,默认值]):安全地获取键对应的值,如果指定键不存在则返回None,如果还指定了默认值则返回该默认值
    • d["键"]=:添加/修改键值,如果该键不存在,则添加,如果存在则修改
    • del d["键"]:删除指定键,如果键不存在,会产生 KeyError
    • d.pop("键"):删除指定键,并返回被删除的值,如果指定键不存在,产生 KeyError。可以写为d.pop("键",默认值)形式,如果指定键不存在,则返回默认值,如:d.pop("x", None)
    • d.popitem():删除并返回最后插入的键值对
    • d.clear():清空字典,字典对象本身仍然存在,只是变为空字典
    • dict.fromkeys( iterable ):类方法,从可迭代对象获得 key ,该方法常用来在保证元素出现顺序不变的情况下去重(set不保证元素出现顺序),它利用字典键的唯一性去重,如:lst = [1, 2, 3, 2, 4, 1, 5] result = list(dict.fromkeys(lst))
      以下操作返回的是字典视图对象(view),以 d ={'a': 1, 'b': 2} 为例
    • d.keys():返回字典中所有键的动态视图, 如:d.keys() 返回 dict_keys(['a', 'b']),默认情况下遍历字典返回的就是键,因此遍历键可以直接 for key in d 而不需要 for key in d.keys()
    • d.values() :返回字典中的所有值,如:d.values() 返回 dict_values([1, 2]),常用于遍历值:for value in d.values()
    • d.items():返回所有键值对,如:返回 dict_items([('a', 1), ('b', 2)]),常用于同时遍历键、值,如:for key, value in d.items()
    • 字典视图对象可以被显示转换为列表等:如:list(d.keys())、list(d.values())、list(d.items())
    字典更新
    • d.update():用另一个映射或键值对序列更新当前字典,由于是原地更新,返回值为None,如:d = {"a": 1, "b": 2}进行更新 d.update({"b": 20, "c": 3}),已有键会被覆盖,新键会被添加
    • d.setdefault(key, default):如果键存在,返回原来的值;如果键不存在,则将该键值对添加到字典,并返回值,d = {"a": 1};d.setdefault("a", 100) #返回1 d.setdefault("b", 200) # 返回200,最后d = {"a": 1, "b": 200}
    • a | b:合并两个字典,如果存在相同键,右侧字典的值覆盖左侧字典,因此 a |= b 可以原地更新a

    表达式

    标识符

    NAME规则用于标识符、关键字 和软关键字,它们由以下字符组成:

    • 大写字母A-Z和小写字母a-z
    • 下划线 _
    • 数字0-9,但不能作为第一个字符
    • 部分非ASCII字符,如:Unicode字符(包括一些表情)、中文字符等
    • 必须至少包含一个字符,但没有长度上限,大小写敏感
    • 定义变量,不需要let、int等关键字,如:num=10 即可,在Python shell再次输入该变量,会输出该变量的值

    命名习惯

    • 常量通常用全大写表示
    • 普通变量、函数、模块使用下划线命名,而不是小驼峰,如:user_name
    • 类名使用大驼峰,如:class UserAccount
    • 私有/内部变量前面加一个下划线,如:_local_state = None,表示“这是内部使用的,不建议外部直接访问”,但 Python 不会强制阻止访问
    • 避免命名冲突,可以在变量名后添加一个下划线,如:id_ = 123
    • 魔术方法使用双下划线包围,如:__init__

    数值运算

    • 运算符:+-*/=%(四则运算,赋值,取余),**(乘方),//(向下取整除法),**优先级比-高,比如:-3**2会被解析为-(3**2)
    • python中的数值是不可变类型,因此python不支持 i++ 、i--这类原地修改 i 的运算,只能重新赋值(重新绑定name):i+=1、i-=1
    • 矩阵乘法运算符:@,如:a @ b,但是Python 内置数值类型没有实现 @,通常由 NumPy 等第三方类型实现
    • 多个表达式用,号分隔,返回的结果是元组,如:x=10 y=20 执行 x+y,x*y,x/y 由于逗号的关系,返回结果是个元组 (30, 200, 0.5)

    位运算

    • 移位运算符:<<(左移),>>(右移)
    • 位运算符:&(AND),^(XOR),|(OR)
    • 按位取反:~

    比较运算

    • 比较运算符:<、>、<=、>=、==、 !=
    • Python中的比较运算可以连续书写,如:a < b < c等价于 a < b and b < c,但 b 只求值一次

    身份比较与成员测试

    • is/is not:判断两个名称是否指向同一个对象,如:a is b,它与 == 不同,a == b是判断值是否相等
    • in / not in:判断元素是否属于某个容器,具体判断方式由对象类型决定,也可以通过 __contains__() 自定义

    逻辑运算

    • and:与运算,如:x and y
    • or:或运算,如:True or True
    • not:非运算,如:not True
    • and和or是短路运算符
    • Python 的 and、or 不一定返回 True / False,而是返回实际参与运算的对象,如:x and y,如果 x 为假,直接返回 x;如果x 为真,计算并返回 y。因此可用name = user_name or "unknown"提供默认值

    条件表达式(三元运算符)

    值1 if 条件 else 值2:又称三元运算符,用于根据条件产生不同的值,条件为真,计算并返回值1,否则返回值1,如:print("yes" if flag else "no")

    海象运算符

    变量 := 表达式:用于给变量赋值的同时,返回被赋的值

    if (n := len(data)) > 10: print(n)

    解包

    解包(Unpacking)是一种将可迭代对象(如列表、元组、字符串等)中的元素拆分并赋值给多个变量的语法(特性类似于JS中的解构赋值,但有区别),Python中的解包可以通过以下方式:

    • 通过相同数量的变量-元素解包:如:a, b, c = (1, 2, 3),变量 a,b,c 都将获得对应的值,该方法可以直接交换变量而不需要中间变量,如:a,b=1,2 #定义变量时解包 a,b=b,a #交换变量时解包
    • 通过*号收集多余元素,可以放在任意位置,多余的元素会被打包到一个列表里(即使只有一个元素),但一个表达式中只能用一次
    1.接收多个元素 a, *b = [1, 2, 3, 4] print(a) # 1 print(b) # [2, 3, 4] 2.*可以位于任意位置 first, \*middle, last = (1, 2, 3, 4, 5) print(first) # 1 print(middle) # 存入[2, 3, 4] print(last) # 5 3.可用于连续展开元素,如果是用于展开迭代对象的元素,可用多个* a = [1, 2] b = [3, 4] [*a, *b] # 展开为 [1, 2, 3, 4] [a,b] # 会展开为 [[1, 2], [3, 4]]
    • 通过_或*_收集不关心的值
    a,_,b,_=(10,20,30,40) print(a) # 10 print(b) # 30
    • *用于解包普通可迭代对象,**则用于解包映射对象(Python中通常是字典)
    1.构造字典 a = {"x": 1} b = {"y": 2} {**a, **b} #构造出{'x': 1, 'y': 2} 2.用于函数传参时解析字典 def add(a, b, c): return a + b + c params = {'a': 1, 'b': 2, 'c': 3} print(add(**params)) #解析字典 6

    推导式

    列表/集合/字典推导式

    推导式(comprehension)用于根据一个可迭代对象快速构造新的列表、集合或字典。列表、集合、字典推导式的基本结构几乎相同,区别主要在于最终生成元素的形式以及使用的括号,以列表推导式为例,表达式格式为:
    [ 元素生成表达式 for语句 [ if语句 for语句 if语句.... ]]

    • 集合/字典推导式只需要相应地修改括号和表元素生成表达式
    • for 语句可提供多个,以形成嵌套的 for 循环语句
    • 可通过if语句执行判断
    • 每次求的元素只能为一个/一组整体,不允许 [x,y for ......] 但可以 [(x,y) for ......],其中(x,y)为一个元组
    1.简单的列表/集合/字典推导式 [x**2 for x in range(5)] #列表推导式 [0, 1, 4, 9, 16] {x % 3 for x in range(10)} #集合推导式 {0, 1, 2} {k: len(k) for k in ["cat", "python", "OS"]} #字典推导式 {'cat': 3, 'python': 6, 'OS': 2}
    2. 可以有多个for [f"{x}--{y}" for x in range(3) for y in range(2)] 返回 ['0--0', '0--1', '1--0', '1--1', '2--0', '2--1'] 它的本质是 for 循环嵌套: result = [] for x in range(3): for y in range(2): print(f"{x}--{y}")
    3.可以用if语句过滤数据 [f"{x}--{y}" for x in range(4) if x%2==0 for y in range(4) if y%2==1] x只要偶数,y只要奇数 输出 ['0--1', '0--3', '2--1', '2--3']
    4.如果要用if..else..条件表达式选择数据,则应当写在元素生成表达式中 [x if x%2==0 else x*100 for x in range(5)] 输出 [0, 100, 2, 300, 4]
    5. 两个数据需要从不同的迭代对象获取 name = "Jay Tom Blues Ken" scores = (60, 65, 71, 68) 利用zip()拼接数据源 {name:score for name,score in zip(name.split(" "),scores)} 输出 {'Jay': 60, 'Tom': 65, 'Blues': 71, 'Ken': 68}
    6.推导式不允许一次生成多个元素,因此通常将多个元素组成一个元组一起获得 [(x,y) for x,y in zip([1,2,3,4],[11,22,33,44])] 获得 [(1, 11), (2, 22), (3, 33), (4, 44)] 若要继续拆解元素,可用第2个for处理前一个for的结果 [v for x,y in zip([1,2,3,4],[11,22,33,44]) for v in (x,y)] 输出 [1, 11, 2, 22, 3, 33, 4, 44] 语义更清晰的写法是不使用列表推导式: result=[] for x,y in zip([1,2,3,4],[11,22,33,44]): result.extend((x,y))

    生成器表达式

    生成器表达式(generator expression)与列表推导式语法基本相同,但不会立即生成完整列表,而是产生一个生成器,用于根据可迭代对象逐个产生数据。语法与列表推导式基本相同,但外层使用()包裹,并且有以下特点:

    • 返回一个生成器对象(generator object),可以用循环语句、next()逐个获取元素
    • 采取惰性求值,列表推导式立即计算并创建列表,生成器表达式则保存生成规则,在迭代时逐个计算,因此它适合处理大量数据而不是一次性生成数据的场景,可以减少内存占用
    • 生成器表达式本身只能产生一次数据,如:g = (x for x in range(3)) 首次获取生成器对象 list(g) #[0, 1, 2],再次获取list(g) 给出 []
    • 语法和推导式类似
    e.g创建一个生成器,逐个获取数据 g1=((x,y) for x in range(5) for y in range(6,10)) 可使用next()因此获取元素 next(g1) # (0, 6) next(g1) # (0, 7) next(g1) # (0, 8) 也可以使用for遍历 for x in g1: print(x) 输出 (0, 9) (1, 6) (1, 7) (1, 8) (1, 9)....

    语法练习题

    • 给定 n=-17,使用 // 和 % 计算 n//5、n%5,并解释为什么结果如此。
    • 给定 s="hello",统计字符串长度,并分别取得第一个、最后一个和倒数第三个字符。
    • 给定 s="Python Programming",使用索引和切片取得 "Python"、"Programming"、"Pyth" 和逆序字符串。
    • 给定 s=" Hello, Python! ",去除两端空白,并将结果转换为大写、小写和首字母大写形式。
    • 给定 s="apple,banana,orange,pear",按逗号分割成 list,再使用 join() 恢复成字符串。
    • 给定 s="hello world",判断其中是否包含 "world",并统计字符 "l" 出现次数。
    • 给定 s="a-b-c-d",使用 split() 得到列表,再将列表元素用 ":" 连接。
    • 给定 s="Python123",判断它是否只包含字母、只包含数字、是否以 "Py" 开头、是否以 "123" 结尾。
    • 创建 list=[10,20,30,40,50],完成索引访问、负索引访问、切片、逆序和步长为 2 的切片。
    • 给定 list=[1,2,3],分别使用 append()、extend()、insert() 添加元素,并观察三者区别。
    • 给定 list=[1,2,3,2,4,2],统计 2 的出现次数,找到第一个 4 的位置,并删除一个 2。
    • 给定 list=[5,3,8,1,9,2],分别使用 sorted() 和 list.sort() 排序,并比较返回值。
    • 给定 list=[1,2,3,4,5],使用切片完成:删除前两个元素、删除最后一个元素、在中间插入多个元素。
    • 给定 list=["a","b","c"],使用 enumerate() 得到元素及其索引。
    • 给定 list=[1,2,3],将其转换为 tuple,再将 tuple 转回 list。
    • 创建 tuple=(10,20,30,40),完成索引、切片、解包和成员判断。
    • 给定 tuple=(1,2,2,3,2),统计 2 的数量并找到第一个 3 的索引。
    • 创建 tuple=(1,[2,3],4),修改其中 list 的内容,并观察 tuple 本身是否可以包含可变对象。
    • 创建 dict={"name":"Tom","age":20,"score":95},分别通过键访问、修改、新增和删除元素。
    • 给定 dict={"a":1,"b":2,"c":3},分别使用 keys()、values()、items() 遍历字典。
    • 给定 dict={"apple":3,"banana":5},判断 "apple" 和 "orange" 是否为键。
    • 给定 dict={"a":1,"b":2},尝试访问不存在的键,分别使用 [] 和 get(),观察区别。
    • 创建两个字典 {"a":1,"b":2} 和 {"b":3,"c":4},使用 | 合并它们,并观察重复键的结果。
    • 给定 dict={"name":"Alice","scores":[80,90,95]},访问嵌套 list,并将 90 修改为 100。
    • 创建 set={1,2,3,4},完成添加、删除、成员判断,并观察重复元素的行为。
    • 给定两个集合 A={1,2,3,4}、B={3,4,5,6},分别计算并集、交集、差集和对称差集。
    • 给定 list=[1,2,2,3,3,3,4],转换成 set 去除重复元素,再转换回 list。
    • 比较 list、tuple、set 在成员判断、索引访问和重复元素方面的区别。
    • 创建 bytes=b"Python",完成索引、切片、len() 和成员判断。
    • 给定 b"hello",分别取得第一个字节和前两个字节,观察索引与切片返回的类型是否相同。
    • 给定字符串 s="你好,Python",使用 UTF-8 编码转换为 bytes,再使用 decode() 恢复为 str。
    • 给定 b"Python + 14",解码为字符串后替换其中的版本号,再重新编码为 bytes。
    • 给定数字列表 [65,66,67,68],转换为 bytes,并观察结果;再将 bytes 转换为 list。
    • 给定 bytes 数据 b"12345",将其转换为 list、str,并比较直接 str(b) 与 b.decode() 的区别。
    • 给定字符串 "hello",分别转换成 list、tuple、set,观察三种结果的结构差异。
    • 给定 list=["1","2","3","4"],将每个元素转换为整数,得到 [1,2,3,4]。
    • 给定 list=[1,2,3,4],将每个整数转换为字符串,得到 ["1","2","3","4"],再使用 join() 拼接。
    • 给定 tuple=("a","b","c"),转换为字符串 "abc",再转换回字符列表。
    • 给定字符串 "abcabc",转换为 set,观察结果;再将 set 转换为 list 并排序。
    • 给定 list=[("name","Alice"),("age",20),("score",95)],将其转换为 dict。
    • 给定 dict={"a":1,"b":2,"c":3},转换 keys()、values()、items() 为 list 和 tuple。
    • 给定 dict={"a":1,"b":2,"c":3},把所有键转换为 list,把所有值转换为 set。
    • 给定两个 list:[1,2,3,4] 和 [3,4,5,6],分别使用集合运算求共同元素、只存在于第一个列表的元素和所有不重复元素。
    • 给定字符串 "red,green,blue",转换为 list、tuple、set,并分别恢复成字符串。
    • 给定整数 123456,转换成字符串后反转,再转换回整数,得到 654321。
    • 给定 bytes=b"hello",先转换成 list,再修改其中一个字节,最后重新转换成 bytes。
    • 给定 bytearray(b"hello"),修改其中一个字节,再转换成 bytes 和 str。
    • 给定 frozenset([1,2,3]),进行成员判断、集合运算,并尝试修改它。
    • 创建一个包含 list、tuple、set、dict、bytes 的混合列表,分别访问其中元素并判断各元素类型。
    • 给定 data={"name":"Alice","tags":["python","linux"],"ports":{80,443}},分别访问和修改嵌套的 list、set 元素。
    • 给定用户输入形式的字符串 "Alice,20,Python",将其拆分后转换成包含 name、age、language 的 dict。
    • 给定字符串 "1,2,3,4,5",转换成整数列表,再计算总和、最大值、最小值和平均值。
    • 给定字符串 "apple banana apple orange banana apple",统计每个单词出现次数,结果保存为 dict。
    • 给定 list=[1,2,3,2,4,1,5],在保持原始出现顺序的前提下去除重复元素。
    • 给定 bytes=b"\x48\x65\x6c\x6c\x6f",解码或转换它,得到 "Hello"。
    • 综合题:给定字符串 "Python,Python,Java,C,Python,Go",统计每种语言出现次数,并保存为字典,并得到不重复语言集合、按出现顺序去重后的列表以及按字母排序后的列表。
    s = "Python,Python,Java,C,Python,Go" 1.统计次数与去重集合 \# 字典推导 result = {word: s.split(",").count(word) for word in s.split(",")} \# 性能更高:先用set去重 words = s.split(",") result = {word: words.count(word) for word in set(words)} \# 开发推荐,collections.Counter from collections import Counter result = dict(Counter(s.split(","))) 2. 按出现顺序去重后的列表 d = dict.fromkeys(s.split(",")) l = list(d) 3.按字母排序 l.sort()
    上一篇:python下
    下一篇:基于certbot获取TLS证书
    z z z z z