长文总结 | Python基础知识点,建议收藏

测试基础-Python篇 基础①

变量名命名规则 - 遵循PEP8原则

  • 普通变量:max_value

  • 全局变量:MAX_VALUE

  • 内部变量:_local_var

  • 和关键字重名:class_

  • 函数名:bar_function

  • 类名:FooClass

  • 布尔类型的变量名用 is,has 这类词语前缀

    is_superuser

    has_errors

    allow_empty

  • 释义为数字的单词

    port

    age

    radius

  • 以_id 为结尾的单词

    user_id

    port_id

  • 以 length/count 开头或结尾的词

    length_of_username

    max_length

    users_count

    注:不要用名词的复数形式来作为 int 类型的变量名,因为名词的负数形式更像是一个容器。建议使用 number_of_apples 或 trips_count;

  • 超短命名

    数组索引三剑客 i、j、k

    某个整数 n

    某个字符串 s

    某个异常 e

    文件对象 fp

变量注解

在Python3.5之后,可以使用类型注解功能来注明变量类型,在变量后添加类型,并用冒号隔开;

  1. def repeat_message(message: str, count: int) -> str:

  2. return message * count

算术运算符

  • // 取整除

  • % 取余

  • ** 幂

不同类型变量之间的计算

  • 数字型变量之间可以直接计算;

  • 如果变量是 bool 型,在计算时,true 对应的是1,false 对应的是0;

  • 字符串变量之间使用 + 拼接字符串。

获取输入的信息-input

  • 字符串变量 = input("提示信息")

input 输入的数据类型都是字符串类型

格式化输出

  • %s --字符串

  • %d --有符号十进制整数,%06d 表示输出的整数显示位数,不足的地方使用 0 补全

  • %f --浮点数,%.2f 表示小数点后只显示两位,会四舍五入

  • %% --输出%

    vb1 = 'Tom'print("hello %s" % vb1)vb2 = 5print('有符号十进制整数:%d' % vb2)print('输出显示位数的整数:%06d' % vb2)vb3 = 3.1415926print('保留两位小数:%.2f' % vb3)print('保留三位小数:%.3f' % vb3)vb4 = 80print('正确率为:%d%%' % vb4)--------------------------------------------------------------------hello Tom有符号十进制整数:5输出显示位数的整数:000005保留两位小数:3.14保留三位小数:3.142正确率为:80%

逻辑运算

  • and:

    条件1 and 条件2

  • or:

    条件1 or 条件2

  • not:(取反)

    not 条件

    a = 10b = 20c = 10if c == a and c == b:print('right')else:print('error')-------------------------------error
    
    a = 10b = 20c = 10if c == a or c == b:print('right')else:print('error')-------------------------------right
    

循环-while

初始条件设置 -- 通常是重复执行的 计数器

while 条件 1:

条件满足时,做的事情 1

条件满足时,做的事情 2

条件满足时,做的事情 3

......

while 条件 2:

条件满足时,做的事情 1

条件满足时,做的事情 2

条件满足时,做的事情 3

......

处理条件 2

处理条件 1

print 函数增强

在默认情况下,print 函数输出内容之后,会自动在内容末尾增加换行;

如果不希望末尾增加换行,可以在 peint 函数输出内容的后面增加,end=""

其中""中间可以指定 print 函数输出内容之后,继续希望现实的内容;

语法格式如下:

print("*",end="")

转义字符

  • \t--在控制台输出一个制表符,协助在输出文本时,垂直方向,保持对齐

  • \n--在控制台输出一个换行符

  • \r--回车

  • \--反斜杠符号

  • \'--单引号

  • \"--双引号

列表

  • 列表通过索引取值,列表索引从0开始,且不能超过范围;

  • len(列表)--获取列表的长度

  • 列表.count(数据)--数据在列表中出现的次数

  • 列表.index(数据)--获取数据第一次出现的索引

  • del 列表 [索引]--删除指定索引的数据

  • 列表.remove[数据]--删除第一个出现的指定数据

  • 列表.pop--删除末尾数据

  • 列表.pop(索引)--删除指定索引的数据

  • 列表.insert(索引,数据)--在指定位置插入数据

  • 列表.append(数据)--在末尾追加数据

  • 列表.extend(列表 2)--将列表2的数据追加到列表1

  • 列表.sort()--升序排序

  • 列表.sort(reverse=True)--降序排序

  • 列表.reverse() 反转/逆序

元祖

  • Tuple(元组)与列表类似,不同之处在于元组的 元素不能修改;

  • 创建空元组:info_tuple = ()

  • 元组中只包含一个元素时,需要在元素后面添加逗号:info_tuple = (50, )

  • len(元组)--获取元组的长度 n+1;

  • 元组.count(数据)--数据在元组中出现的次数;

  • 元组 [索引]--从元祖中取值;

  • 元组.index(数据)--获取数据第一次出现的索引。

元组和列表之间的转换

  • 使用 list 函数可以把元组转换成列表

    list(元组)

  • 使用 tuple 函数可以把列表转换成元组

    tuple(列表)

字典

  • Python 里的字典在底层使用了哈希表 (hash table) 数据结构

  • 和列表的区别:列表 是 有序 的对象集合 字典 是 无序 的对象集合

Python3.6 之后的字典是有序的,如果解释器版本没有那么新,也可以使用 collections 模块里的 OrderedDict 方法保证字典的有序性。

OrderedDict 与新版字典在比较上面的区别:在对比两个内容相同但顺序不同的字典时,新版字典会返回 True,OrderedDict 则会返回 False。

  1. from collections import OrderedDict

  2. d = OrderedDict()

  3. d['one'] = 1

  4. d['two'] = 2

  5. print(d)------------------------------------------------------------

  6. OrderedDict([('one', 1), ('two', 2)])

  • 键必须是唯一的;

  • 值可以取任何数据类型,但键只能使用字符串、数字或元组;

  • 字典.keys()--所有 key 列表;

  • 字典.values()--所有 value 列表;

  • 字典.items()--所有(key,value)元组列表;

  • 字典 [key]--可以从字典中取值,key 不存在会报错;

    1.返回的数据类型类似列表,但不是真正意义的列表,没有 append() 方法;

    2.但是可以用于 for 循环;

    3.可以用 list() 方转换成真正的列表;

  • 字典.get(key)--可以从字典中取值,key 不存在不会报错;

  • del 字典 [key]--删除指定键值对,key 不存在会报错;

  • 字典.pop(key)--删除指定键值对,并且返回删除键对应的值,key 不存在会报错;

  • 字典.pop(key, default=msg)--删除指定键值对,并且返回删除键对应的值,key 不存在不会报错,会返回 msg;

  • 字典 popitem() 方法返回并删除字典中的最后一对键和值。

  • 字典.clear()--清空字典;

  • 字典 [key] = value

    如果 key 存在,修改数据

    如果 key 不存在,新建键值对

  • 字典.setdefault(key,value)

    如果 key 存在,不会修改数据

    如果 key 不存在,新建键值对

  • 字典.update(字典2)--将字典2的数据合并到字典1,如果字典2中有和字典 1 重复的键值对,则替换字典 1 中的键值对;

  • 生成字典的方法:d = dict.fromkeys(["name","age","code"],0) #0 为默认值

字符串

  • 拼接多个字符串,使用 str.join 和 +=同样好用;

  • len(字符串)--获取字符串的长度;

  • 字符串.count(字符串)--小字符串在大字符串中出现的次数;

  • 字符串 [索引]--从字符串中取出单个字符;

  • 字符串.index(字符串)--获得小字符串第一次出现的索引;

  • string.istitle() | 如果 string 是标题化的 (每个单词的首字母大写) 则返回 True;

  • string.startswith(str) | 检查字符串是否是以 str 开头,是则返回 True;

  • string.endswith(str) | 检查字符串是否是以 str 结束,是则返回 True;

  • string.find(str, start=0, end=len(string)) | 检测 str 是否包含在 string 中,如果 start 和 end 指定范围,则检查是否包含在指定范围内,如果是返回开始的索引值,否则返回 -1

  • string.index(str, start=0, end=len(string)) | 跟 find() 方法类似,不过如果 str 不在 string 会报错;

  • string.replace(old_str, new_str, num=string.count(old)) | 把 string 中的 old_str 替换成 new_str,如果 num 指定,则替换不超过 num 次;

  • string.capitalize() | 把字符串的第一个字符大写;

  • string.title() | 把字符串的每个单词首字母大写;

  • string.lower() | 转换 string 中所有大写字符为小写;

  • string.upper() | 转换 string 中的小写字母为大写;

  • string.swapcase() | 翻转 string 中的大小写;

字符串 - 切片

  • 切片方法适用于字符串、列表、元组;

  • 字符串 [开始索引:结束索引:步长];

  • 切片:正反向索引(正:从 0 开始,反:从-1 开始)

  • 切片索引:[startENDstep]

  • start:开始截取的位置,包含在截取内容内

  • end:结束截取的位置,结束截取的位置并不包含

  • step:截取的步长,默认值为 1

  • step:为正,表示从左到右进行截取,start 必须在 end 之前(从左开始算前,下标必须从左到右)

  • step:为负,表示从右到左进行截取,start 必须在 end 之前(从右开始算前,下标必须从右到左)

  • s = "hello,world"

    print(s[:]) # 取全部

    print(s[1:]) # 从第 2 位取到最后

    print(s[:-1]) # 从开始取到倒数第二位

    print(s[::2]) # 步长为 2

    print(s[::-1]) # 反序

指定的区间属于左闭右开型 [开始索引, 结束索引) => 开始索引 >= 范围 < 结束索引

从 起始位开始,到 结束位的前一位 结束(不包含结束位本身)

从头开始,开始索引 数字可以省略,冒号不能省略

到末尾结束,结束索引 数字可以省略,冒号不能省略

步长默认为 1,如果连续切片,数字和冒号都可以省略

索引的顺序和倒序:

在 Python 中不仅支持 顺序索引,同时还支持 倒序索引

所谓倒序索引就是 从右向左 计算索引

最右边的索引值是 -1,依次递减

字符串格式化

  • 优先使用 f-string 方式
  1. # 将username靠右对齐,左侧补空格一共到20位username = 'Lili'print(f'{username:>20}')-------------------------------------

  2. Lili

  • 对参数复用时可以使用 str.format 方式

    username = 'Lily'sore = 10print('{0}:{0}的成绩是{1}'.format(username, sore))

集合

  • 集合是一个无序的可变容器类型,他最大的特点就是成员不能重复

  • 要初始化一个空集合只能调用 set() 方法,因为{}表示的是一个空字典,而不是一个空集合

  • 集合也有自己的推导式-nums = {n for n in range(10) if n % 2 == 0}

  • 集合是可变类型,可以通过.add() 追加元素

  • 可以使用 update 方法可以将一个可迭代元素更新到集合中

    s1 = set([1,2,3])s2 = set([2,3,4])s1.update(s2)s1.update('hello')print(s1)------------------------{1, 2, 3, 4, 'o', 'h', 'e', 'l'}

  • 使用.remove() 可以删除集合中的元素,但元素不存在会报错-KeyError:

  • 使用.discard() 可以删除集合中的元素,元素不存在也不会报错

  • 集合的元素不可以修改,只能先删再加

  • 我们可以使用 in 判断某个元素是否在某个集合中,不能在集合中取值,只能使用 for 循环遍历集合中的元素

  • 集合只能存放可哈希对象

    s1 = set([1,2,3])s1.add([1])-----------------------TypeError: unhashable type: 'list'

集合的运算

集合支持集合运算,比如交集、并集、差集。所有的操作都可以用两种方式:方法和运算符;

  • 交集

    fruits_1 = {'apple','orange','pineapple'}fruits_2 = {'tomato','orange','grapes','mango'}print(fruits_1 & fruits_2)-----------------------------{'orange'}

  • 并集

    fruits_1 = {'apple','orange','pineapple'}fruits_2 = {'tomato','orange','grapes','mango'}print(fruits_1 | fruits_2)----------------------------------------------------------{'tomato', 'pineapple', 'orange', 'apple', 'grapes', 'mango'}

  • 差集(前有后没有)

    fruits_1 = {'apple','orange','pineapple'}fruits_2 = {'tomato','orange','grapes','mango'}print(fruits_1 - fruits_2)------------------------------------{'apple', 'pineapple'}

  • symmetric_difference:返回两个集合中不重复的元素

    fruits_1 = {'apple','orange','pineapple'}fruits_2 = {'tomato','orange','grapes','mango'}print(fruits_1.symmetric_difference(fruits_2)){'apple', 'mango', 'tomato', 'pineapple', 'grapes'}

  • issubset:用于判断集合的所有元素是否都包含在指定集合中

    fruits_1 = {'apple','orange','pineapple'}fruits_2 = {'apple','orange','pineapple','water'}print(fruits_1.issubset(fruits_2))print(fruits_2.issubset(fruits_1))--------------------------------------------------TrueFalse

Python 循环结构

  • 什么时候用 for:当循环次数是一定的,或者是循环对象是一定的,比如说在一个固定的字符串或列表中进行循环,那么最好使用 for

  • 什么时候用 while:当循环次数不是一定的,只是满足某个条件时才进行循环,那么最好使用 while

  • 没有 do...while...循环

  • 循环里面加 else:当循环执行完毕时,else 才会执行;如果循环在中间退出,则 else 不会运行

  • break&continue:不管是 break 还是 continue 都只作用于当前循环

匿名函数-lambda

  • lambda 关键字能够帮我们创建小型的匿名函数:

  • lambda x:express

  • lambda 返回的是该匿名函数的指针

  • func = lambda x,y:x*y

    print(func(2,3))

类定义
  • 类名首字母大写,多个字母连接一起

  • 默认继承 object 类,若继承其他类则在类名后加(继承父类)

类方法
  • 实例方法

    1、只能通过对象 (实例) 调用的方法

    2、实例方法在定义时总是以 self 作为第一个参数

    3、实例方法在调用时不需要传入 self,这个实例本身会自动传到方法中作为 self

  • 初始化方法 (init ())

    1.不需要显式调用,在初始化对象时会有 python 自动调用

    2.初始化方法一般只在定义对象属性的时候才会定义

  • 类方法

    1、可以直接通过类名调用的方法,也可以通过实例调用

    2、类方法必须通过*@* classmethod装饰器进行装饰

    3、所有的类方法第一个参数必须是 cls

    4、类方法不能访问实例属性,只能访问类属性

  • 属性方法

    使用场景:属性方法对应的属性的值无法直接确定,要通过一系列的操作才能得到这个值,而且用户不关心这个操作过程,只想得到这个值。

    定义:当成属性使用的方法,调用属性方法时不需要加 ()

  • 静态方法

    1、通过*@* staticmethod装饰器来进行装饰的方法

    2、静态方法既不能访问实例属性,也不能访问类属性

    3、可以通过类名直接调用,也可以通过对象调用

类的三大特征
  • 封装

    暴露接口,隐藏细节

  • 继承

    1.子类通过继承直接获得父类的全部属性和方法,实现代码复用

    2.初始化的几种情况:

    2.1 当子类中没有定义init () 方法,则初始化子类时将默认使用父类的初始化方法,并传入对应的参数

    2.2 当子类定义了自己的初始化方法,但没有调用父类的初始化方法,则父类中的相关属性不会被初始化

    2.3 若在子类中重新定义了 init 方法,若仍要继承父类的属性,则需要显示调用父类的 init 方法:super().init()

  • 多态

类的反射
  • 反射原理

    通过字符串的形式在运行时动态修改程序的变量、方法及属性,所有的修改都在内存中进行,所以他并不会实际修改代码,主要目的就是提高代码在运行时的灵活性;

  • 反射相关的方法

    hasattr 输入一个字符串,判断对象有没有这个方法或属性;

    getattr 获取对象属性值或方法的引用,如果是方法,则返回方法的引用,如果是属性,则返回属性的值,如果该方法或属性不存在,则抛出异常;

    setattr 动态添加一个方法或属性;

    delattr 动态删除一个方法或属性。

异常处理

Python 异常处理依赖的关键字:

try

except

else

finally

  • try

    try 块里面放置所有可能引起异常的代码,一个异常处理块里面只能有一个 try;

  • except

    放置要处理的异常类型和相应语句块,用于表明该 except 要处理的异常类型;

    一个异常处理块里面可以跟 1 到 n 个 except 块;

    每个 except 块后面可以跟 1 到 n 个异常类型,也可以不跟任何异常类型;

  • else

    如果 try 块里面的语句没有引起异常,则会运行 else 里面的语句;

  • finally

    主要用于回收再 try 块里面打开的物理资源,异常处理机制会保证 finally 块一定会被执行;

  • 异常处理语法结构

    1.只有 try 是必须的

    2.如果没有 try,就不能有 except 和 finally

    3.except 块和 finally 块都是可选的,但 except 和 finally 必须出现其中之一,也可以同时出现

    4.可以有多个 except 块,但捕获父类异常的 except 块要写在捕获子类异常的 except 块的后面

    5.多个 except 块必须位于 try 块之后,finally 块必须位于所有块的最后

IO 读写 - 文本文件

  • open (path,mode)

    默认是 r:只读模式,文件必须事先存在,不主动生成文件,从文件开头开始读;

    r+:读写模式,文件也必须事先存在,不主动生成文件,从文件开头开始读或写;

    w:只写模式,如果用 w 模式打开,一律会清空之前文件的所有内容,如果文件不存在,则自动创建文件,从头开始写;

    w+:读写模式,也会清空之前文件的所有内容,如果文件不存在,则自动创建文件,从头开始写;

    a:追加模式,只写,不会清空以前文件的内容,主动生成文件,从文件尾开始写入;

    a+:追加模式,读和写,不会清空以前文件的内容,主动生成文件,从文件尾开始写入或读取;

    二进制读写,一般用于图片或音视频:rb+,wb+,ab+;

  • 查看和设置文件指针位置:

    1. with open('user.txt', 'a+') as f:

    2. # 将文件指针重置至开始位置(这样就不会导致f.readlines()读不到数据了) f.seek(0)

    3. # 返回文件指针位置 print(f.tell())

  • with 是 python 中的上下文管理器,它会自动帮你管理文件的句柄

    1. with open(r'D:\testlog.txt') as f:for line in f.readlines():

    2. print(line,end='')

  • 文件与文件夹

    windows 文件路径用反斜线,Linux 文件路径用正斜线,要想将程序在不同系统上运行,则可用 os.path.join() 方法;

  1. myFiles = ['accounts.txt','details.csv','invite.docx']

  2. for filename in myFiles:

  3. print(os.path.join('c:\\User\\asweigart',filename))-----------------------------------------------------------------------------------------c:\User\asweigart\accounts.txtc:\User\asweigart\details.csvc:\User\asweigart\invite.docx

其余相关知识点附张图吧:

多线程和多进程编程

  • 概念

    程序:指的是一段静态的代码指令;

    进程:正在执行的程序,将静态的执行代码运行起来,进程内拥有该程序执行所需的全部资源;

    线程:是指正在执行程序的最小单元。一个进程中至少必须有一个线程(主线程),在程序中线程是独立的可运行的流;

    多线程:在单个程序中同时运行多个不同的线程,完成不同的工作;

  • 进程特征

    独立性:进程是系统中独立存在的实体,拥有独立的资源空间;

    动态性:进程拥有自己的生命周期;

    并发性:多个进程可以在单个处理器上并发执行,互不影响;

  • 线程特征

    每个线程都有自己的堆栈,自己的程序计数器,自己的局部变量,这里体现了程序的独立性;

    在相同父进程下的所有线程共享进程内所有资源,可以实现线程间的消息互通;

    多个线程之间也可以并发执行,互不影响;

  • 创建多线程-threading

    1.使用 threading 模块的 Thread 类的构造器创建线程对象。在创建线程对象时使用 target 参数指定函数线程的执行体;

    2.调用线程对象的 start() 方法启动线程;

  • 通过 join 方法去阻塞主线程

    d = Demo()t1 = threading.Thread(target=d.music,args=('摇篮曲',))t2 = threading.Thread(target=d.movie, args=('灰太狼',))t1.start()t2.start()t1.join()t2.join()
    
  • 设置守护线程

    主线程结束后立即结束所有设置为守护线程的子线程;

  • 多线程锁

    1. import threadingbalance = 0lock = threading.RLock()def change_it(n):lock.acquire()try:

    2. global balance

    3. balance += n

    4. balance -= nfinally:

    5. lock.release()def run_threading(n):for i in range(100000000):

    6. change_it(n)t1 = threading.Thread(target=run_threading, args=(5,))t2 = threading.Thread(target=run_threading, args=(5,))t1.start()t2.start()t1.join()t2.join()

GIL 全局解释器锁

什么是 GIL 全局解释器锁:

GIL(Global Interpreter Lock)是 Python 的一个重要特性,它是一种机制,用于保护多线程环境下共享内存数据的完整性。它锁定了整个解释器,只允许一个线程同时执行 Python 字节码,从而避免多线程下出现数据竞争问题。这意味着即使使用多核 CPU,Python 程序也不能充分利用多核优势。GIL 在性能上可能带来一定的影响,因此不适合处理需要大量的 CPU 运算的任务。

什么条件下会释放 GIL:

当前活跃线程遇到 IO 等待,比如要访问网络或建立数据库链接等情况;

活跃线程执行了 100 个字节码的程序后,GIL 也会释放该线程的锁,然后与其他线程参与竞争;

python 的多线程适合场景:

python 的多线程只适合于 IO 密集型应用,对于计算密集型的应用最好使用多进程或协程的方式解决;

可迭代对象

  • 通俗说,可迭代对象就是可以放在 for 循环内进行迭代的对象

    比如列表、字典、元祖、字符串;

  • 判断一个可迭代对象的依据是什么:

    必须至少实现getitemiter这两个方法中的其中一个

迭代器

  • 任何实现了iternext方法的对象都是迭代器(这两个方法必须同时实现);

  • 其中iter会返回迭代器本身;

  • next会返回迭代器中的下一个元素,如果没有元素了将抛出 stopIteration 异常;

  • 迭代器当然也可以用到 for 循环中;

  • 迭代器实际上就是一种工厂模式。

迭代器和可迭代对象的区别

  • 迭代器是迭代对象的一种,迭代器一定是可迭代对象,可迭代对象不一定是迭代器

  • 一个合法的迭代器,必须同时实现iternext两个魔法方法

  • 可迭代对象只需要实现iter方法即可

  • 判断对象 obj 可迭代的唯一方法就是调用 iter(obj),看返回结果是不是一个迭代器

  • 每个迭代器的被迭代过程是一次性的,可迭代对象则不一定

生成器

  • 特殊的迭代器,只需要使用 yield 关键字,那么就会立即变为一个生成器,也就是说,只要一个函数中包含了一个 yield 关键字(不管几个),那么这个函数就会自动变成一个生成器函数;

  • 生成器一定是一个迭代器,但反之不一定成立;

  • 特点:

    生成器中每次遇到 yield 关键字之后,会返回相应的结果;

    保留函数当前的运行状态,等待下一次调用,下次调用时将从上一次返回 yield 语句处开始执行后面的语句;

  • 生成器的 send 方法可以向函数体内去传递值;

    对于 next 和 send 方法的异同:

    next 和 send 都可以去调用一次生成器,从调用生成器的角度来说,他们的作用完全一样;

    next 无法像生成器内部的变量赋值,但 send 可以;

    next(gen) 等同于 send(None),可以互换;

  • 在生成器中使用 for 循环

    每一次 for 循环相当于调用一次 next;

    for 循环会自动帮助我们处理 stopIteration 异常。

装饰器

  • 定义

    装饰器本质是函数,只是它的作用是为其他函数添加特定的附加功能;

  • 编写装饰器的原则

    装饰器一定不能修改被装饰器的函数的源码;

    装饰器一定不能修改被装饰的函数的调用方式;

  • 实现装饰器的前置知识条件

    1.函数即变量

    函数和普通变量的存储原理是一样的,函数名可以像变量名那样去使用,比如可以进行赋值;

    2.掌握高阶函数相关知识

    符合下面任意条件之一即为高阶函数

    条件一:接收函数名作为参数

    条件二:返回值中包含函数名

    3.掌握函数嵌套相关知识

    通过 def 关键字在一个函数 A 中去定义另外一个函数 B,则函数 B 称为嵌套函数;

    4.装饰器=高阶函数 + 嵌套函数

  • 了解装饰器的本质优势

    1.运行时校验:在执行阶段进行特定校验,当校验不通过时终止执行:

    Django 框架中的用户登录态校验装饰器*@* login_required;

    2.注入额外参数:在函数被调用时自动注入额外的调用参数:

    unittest.mock 模块的装饰器*@* patch;

    3.缓存执行结果:通过调用参数等输入信息,直接缓存函数执行结果:

    functools 模块的缓存装饰器*@* lru_cache;

    4.注册函数:将被装饰函数注册为某个外部流程的一部分:

    Flask 框架的路由注册装饰器*@* app.route;

    5.替换为复杂对象:将原函数 (方法) 替换为更复杂的对象,比如类实例或特殊的描述符对象:

    静态方法的装饰器*@*staticmethod。

正则表达式

正则表达式匹配步骤:

1.import re

2.用 re.compile() 函数创建一个 Regex 对象(记得使用原始字符串)

3.向 Regex 对象的 search() 方法传入想查找的字符串。它返回一个 Match 对象(一般用 mo 接收)

4.调用 Match 对象的 group() 方法,返回实际匹配的字符串

demo:

import re>>> phoneNumRegex = re.compile(r'(\d\d\d)-(\d\d\d-\d\d\d\d)')>>> mo = phoneNumRegex.search('my number is 415-555-4242.')>>> mo.group(1)'415'>>> mo.group(2)'555-4242'>>> mo.group()'415-555-4242'>>> mo.group(0)'415-555-4242'

PLus:

我在学习中,发现正则表达式在任何语言中都占有很大部分的占比,但正则表达式相关的知识点又过于零碎,对于榆木脑袋的我真是学一遍忘一遍。在实际工作中,我自己真正用到正则的地方并不多,再看同事,目前就发现前端同学有可能会用到正则去做一些事情,并且用到的时候都是度娘,一是自己真记不住,二是度娘 copy 过来的多数情况是比自己写要严谨的多的。

基于此,我把正则视为投入产出比太低的事情,仅需要记住个大概印象,真到用时能分清度娘上哪个轮子能用哪个轮子用不了就可以了。

测试基础-Python篇 基础②

常用模块-math

import math

  • print(math.ceil(3.14)) # 取大于等于 x 的最小整数

  • print(math.fabs(-3)) # 取绝对值

  • print(math.floor(3.14)) # 取小于等于 x 的最大整数

  • print(math.fsum([1,2,3])) # 求和

  • print(math.pow(3,4)) #3 的 4 次方 等价于 3**4

  • print(math.sqrt(3)) # 开平方,3 的平方根

常用模块-random

import random

  • print(random.random()) # 返回 [0.0,1.0) 之间的浮点数

  • print(random.randint(10,20)) # 生成 10 到 20 之间的一个随机整数,也就是 [10,20]

  • print(random.randrange(10,20)) # 生成 10 到 20 之间的一个随机整数,也就是 [10,20)

  • print(random.uniform(10,20)) # 生成 10 到 20 之间的一个随机浮点数,也就是 [10,20]

  • print(random.choice([10,20,30])) # 随机从列表选择一个数

  • print(random.choices([10,20,30],k=2)) # 随机从列表选择 k 个数,返回列表形式,取出放回方式,意思是取出的数可以重复

  • print(random.sample(a1,3)) # 随机从列表选 k 个数,返回列表形式,取出不放回方式,意思是取出的数不会重复

  • random.shuffle(a1) # 洗牌,随机变换列表顺序

常用模块-json

  • 用 loads() 函数读取 JSON

    要将包含 JSON 数据的字符串转换为 Python 的值,就将它传递给 json.loads() 函数;

  • 用 dumps() 函数写出 JSON

    将一个 python 值转换成 JSON 格式的数据字符串,就用 json.dumps() 函数;

  1. import jsond = {'name':'Tom','age':26}j = json.dumps(d)d2 = json.loads(j)print(d)print(type(d))print()print(j)print(type(j))print()print(d2)print(type(d2))-------------------------------------{'name': 'Tom', 'age': 26}<class 'dict'>

  2. {"name": "Tom", "age": 26}

  3. <class 'str'>

  4. {'name': 'Tom', 'age': 26}

  5. <class 'dict'>

常用模块-time

  • round() 第一个参数是要处理的数字,第二个可选参数为四舍五入保留的位数,若不传如第二个参数,则默认四舍五入到最近的整数

    import timen = time.time()print(n)n1 = round(n,3)print(n1)------------------------1675392067.29749661675392067.297

  • time.time() ---获取当前时间戳:1675392067.2974966

  • time.sleep(sec) ---睡眠 sec 秒

常用模块-datetime()

  • datetime 模块有自己的 datetime 数据类型:

  • datetime 的一些方法:

  1. import datetimedt = datetime.datetime.now()print(dt)print('dt.year:' + str(dt.year) + '---type:' + str(type(dt.year)))print('dt.month:' + str(dt.month) + '---type:' + str(type(dt.month)))print('dt.day:' + str(dt.day) + '---type:' + str(type(dt.day)))print('dt.hour:' + str(dt.hour) + '---type:' + str(type(dt.hour)))print('dt.minute:' + str(dt.minute) + '---type:' + str(type(dt.minute)))print('dt.second:' + str(dt.second) + '---type:' + str(type(dt.second)))----------------------------------------------------------------------------------------------------------2023-02-03 11:00:08.205691dt.year:2023---type:<class 'int'>

  2. dt.month:2---type:<class 'int'>

  3. dt.day:3---type:<class 'int'>

  4. dt.hour:11---type:<class 'int'>

  5. dt.minute:0---type:<class 'int'>

  6. dt.second:8---type:<class 'int'>

  • Unix 时间戳可以通过 datetime.datetime.fromtimestamp() 转换为 datetime 对象

    import datetimeimport timenow = time.time()date = datetime.datetime.fromtimestamp(now)print(now)print(date)----------------------------------------------------------------------------1675393953.08603122023-02-03 11:12:33.086031

  • datetime对象可以用比较操作符进行比较,后面的datetime对象时"更大"的值

    import datetimeimport timed1 = datetime.datetime.now()time.sleep(1)d2 = datetime.datetime.now()print(d2>d1)-----------------------------------------------True

  • datetime 对象的差的数据类型是'timedelta'

    import datetimeimport timed1 = datetime.datetime.now()time.sleep(1)d2 = datetime.datetime.now()d3 = d2 -d1print(d3)print(type(d3))------------------------------------------------0:00:01.002022<class 'datetime.timedelta'>

  • 要创建 timedelta 对象,就用 datetime.timedelta() 函数

  1. import datetimedt = datetime.timedelta(days=11,hours=10,minutes=9,seconds=8)print(dt)print(type(dt))print(dt.days)print(dt.seconds) # 天不参与计算,10*60*60 + 9*60 + 8 = 36548print(dt.total_seconds()) # 11*24*60*60 + 10*60*60 + 9*60 + 8 = 986948print(str(dt))---------------------------------------------------------------------------------------------------------11 days, 10:09:08<class 'datetime.timedelta'>

  2. 11

  3. 36548

  4. 986948.0

  5. 11 days, 10:09:08

  • 算数运算符可以用于对 datetime 值进行日期运算,例如,要计算今天之后 1000天的日期;

    import datetimedt = datetime.datetime.now()print(dt)thounsandDays = datetime.timedelta(days=1000)print(thounsandDays)print(dt + thounsandDays)------------------------------------------------------------------------------2023-02-06 14:20:46.2650841000 days, 0:00:002025-11-02 14:20:46.265084

常用模块-logging

Logging 库是非常常用的记录日志库,通过 logging 模块存储各种格式的日志,主要用于输出运行日志,可以设置输出日志的等级、日志保存路径、日志文件回滚等;

  • 日志级别

    DEBUG --logging.debug()

    INFO --logging.info()

    WARNING --logging.warning()

    ERROR --logging.error()

    CRITICAL --logging.critical()

  • 使用日志模块

    import logginglogging.basicConfig(format='%(levelname)s %(asctime)s: %(message)s: %(module)s',level=logging.DEBUG)logging.debug('This message should appear on the console')logging.info('So should this')logging.warning('And this, too')-----------------------------------------------------------------------------------------------------DEBUG 2023-02-07 17:04:37,473: This message should appear on the console: logging_practiceINFO 2023-02-07 17:04:37,473: So should this: logging_practiceWARNING 2023-02-07 17:04:37,473: And this, too: logging_practice

  • 将日志记录到文件-logging.basicConfig() 函数接受 filename 关键字。

    import logginglogging.basicConfig(filename='myProgramLog',format='%(levelname)s %(asctime)s: %(message)s: %(module)s',level=logging.DEBUG)logging.debug('This message should appear on the console')logging.info('So should this')logging.warning('And this, too')

  • 禁用日志 只要向 logging.disable() 传入一个日志级别,他就会禁止该级别和更低级别的所有日志消息; logging.disable(logging.CRITICAL) 加在代码前面即可隐藏日志信息(接近 import.logging 的位置更容易找到和管理);

    import logginglogging.disable(logging.CRITICAL)logging.basicConfig(filename='myProgramLog',format='%(levelname)s %(asctime)s: %(message)s: %(module)s',level=logging.DEBUG)logging.debug('This message should appear on the console')logging.info('So should this')logging.warning('And this, too')

常用模块-threading

  • 要得到单独的线程,首先要调用 threading.Thread() 函数,生成一个 Thread 对象。
  1. import timeimport threadingprint('Start of program.')def takeANap():

  2. time.sleep(5)

  3. print('Wake up!')threadObj = threading.Thread(target=takeANap)threadObj.start()print('End of program')----------------------------------------------------------------------------Start of program.End of programWake up!

注意:target 参数名后传的是方法名,不加 (),因为此处并不是调用。

  • 向线程的目标函数传递参数 常规参数可以作为一个列表,传递给 threading.Thread() 中的 args 关键字参数。关键字参数可以作为一个字典,传递给 threading.Thread() 中的 kwargs 关键字参数:
  1. import threadingl = [1,2,3,4]def a(*args):

  2. for _ in args:

  3. print(_)thread_a = threading.Thread(target=a,args=l)thread_a.start()------------------------------------------------------------------------1234

复制代码
  1. import threadingd = {'name': 'Tom', 'age': 18}def b(**kwargs):

  2. for k, v in kwargs.items():

  3. print(str(k) + ':' + str(v))thread_b = threading.Thread(target=b, kwargs=d)thread_b.start()----------------------------------------------------------------------------name:Tomage:18

  • 并发问题需要注意的是:为了避免并发问题,绝不让多个线程读取或写入相同变量。当创建一个新的 Thread 对象时,要确保其目标函数只使用该函数中的局部变量。

  • 线程阻塞-thread.join()

    thread.join() 方法的作用是阻塞当前线程,直到调用 join() 方法的线程结束。也就是说,如果你有多个线程并希望在其中一个线程结束之后再继续执行,则可以使用 join() 方法。

  1. # 不使用join,两个线程并行运行import timeimport threadingdef a():

  2. time.sleep(1)

  3. print('我是a:1/3')

  4. time.sleep(1)

  5. print('我是a:2/3')

  6. time.sleep(1)

  7. print('我是a:3/3')def b():

  8. print('我是b:1/2')

  9. print('我是b:2/2')thread_a = threading.Thread(target=a)thread_b = threading.Thread(target=b)thread_a.start()thread_b.start()-------------------------------------------------------------我是b:1/2我是b:2/2我是a:1/3我是a:2/3我是a:3/3

复制代码
  1. # 使用join,线程b需要等线程a运行完后再运行import timeimport threadingdef a():

  2. time.sleep(1)

  3. print('我是a:1/3')

  4. time.sleep(1)

  5. print('我是a:2/3')

  6. time.sleep(1)

  7. print('我是a:3/3')def b():

  8. print('我是b:1/2')

  9. print('我是b:2/2')thread_a = threading.Thread(target=a)thread_b = threading.Thread(target=b)thread_a.start()thread_a.join()thread_b.start()--------------------------------------------------------------我是a:1/3我是a:2/3我是a:3/3我是b:1/2我是b:2/2

复制代码
  1. # join()方法可以自定义timeout参数,意为最长暂用CPU时间,如果不设置的话就永远等待;import timeimport threadingdef a():

  2. time.sleep(1)

  3. print('我是a:1/3')

  4. time.sleep(1)

  5. print('我是a:2/3')

  6. time.sleep(1)

  7. print('我是a:3/3')def b():

  8. print('我是b:1/2')

  9. print('我是b:2/2')thread_a = threading.Thread(target=a)thread_b = threading.Thread(target=b)thread_a.start()thread_a.join(timeout=2)thread_b.start()-------------------------------------------------------------我是a:1/3我是a:2/3我是b:1/2我是b:2/2我是a:3/3

深拷贝浅拷贝

不可变数据类型(如整型,字符串等)在 Python 中只是拷贝了值,因此在执行浅拷贝时实际上是创建了一个新的副本,而不是拷贝引用。因此,对原数据的更改不会影响到拷贝后的数据。

import copya = 1000b = ac = copy.copy(a)d = copy.deepcopy(a)print(a, b, c, d)print(id(a), id(b), id(c), id(d))a += 1print(a, b, c, d)print(id(a), id(b), id(c), id(d))----------------------------------------------1000 1000 1000 10002518799374640 2518799374640 2518799374640 25187993746401001 1000 1000 10002518805613936 2518799374640 2518799374640 2518799374640

对于可变数据类型,浅拷贝只拷贝第一层中的引用,深拷贝在拷贝时,会逐层进行拷贝,直到所有的引用都是不可变对象为止。

import copya = [1, 2, [3, 4]]b = ac = copy.copy(a)d = copy.deepcopy(a)e = a.copy()f = a[:]print(a, b, c, d, e,f)print(id(a), id(b), id(c), id(d), id(e),id(f))print()a.append(5)print(a, b, c, d, e,f)print(id(a), id(b), id(c), id(d), id(e),id(f))print()a[2].append(6)print(a, b, c, d, e,f)print(id(a), id(b), id(c), id(d), id(e),id(f))----------------------------------------------------[1, 2, [3, 4]] [1, 2, [3, 4]] [1, 2, [3, 4]] [1, 2, [3, 4]] [1, 2, [3, 4]] [1, 2, [3, 4]]2213595331584 2213595331584 2213595362304 2213595356992 2213595443008 2213595442368[1, 2, [3, 4], 5] [1, 2, [3, 4], 5] [1, 2, [3, 4]] [1, 2, [3, 4]] [1, 2, [3, 4]] [1, 2, [3, 4]]2213595331584 2213595331584 2213595362304 2213595356992 2213595443008 2213595442368[1, 2, [3, 4, 6], 5] [1, 2, [3, 4, 6], 5] [1, 2, [3, 4, 6]] [1, 2, [3, 4]] [1, 2, [3, 4, 6]] [1, 2, [3, 4, 6]]2213595331584 2213595331584 2213595362304 2213595356992 2213595443008 2213595442368
  • Python 有多种方式实现浅拷贝,copy 模块的 copy 函数 ,对象的 copy 函数 ,工厂方法,切片等。

  • 赋值符号"=":如果是可变类型,就是引用传递;如果是不可变类型,就是值传递。

  • 浅拷贝的优点:拷贝速度快,占用空间少,拷贝效率高。

  • 因为浅拷贝不能解决嵌套问题,所以引出了深拷贝,深拷贝会遍历并拷贝 items 里所有的内容 - 包括他嵌套的子列表;

对象的可哈希性

  • 不可变的内置类型都是可哈希的,比如 str、int、float、frozenset

  • 可变的内置类型都是不可以哈希的,比如 list、dict

  • 对于不可变容器类型(tuple、frozenset),仅当他的所有成员都不可变时,他自身才是可哈希的

  • 用户定义的类型默认都是可哈希的

注意:只有可哈希对象才能被放进集合或者作为字典的键

sorted() 函数

sorted 函数是 Python 内置函数,用于对可迭代对象进行排序,并返回一个新的列表。

注意:sorted 函数不会改变原来的可迭代对象,而是返回一个新的列表。如果需要改变原来的可迭代对象,可以使用 sort 方法,但它只能用于列表。

参数:

  • iterable:可以是列表、元组、字典等任意可迭代对象。

  • key:一个函数,用于提取每个元素的排序关键字。默认为 None,表示按元素本身的顺序进行排序。

  • reverse:是否按降序排列,默认为 False,表示按升序排列。

enumerate() 函数

enumerate() 适用于任何"可迭代对象",可以用于列表、元祖、字典、字符串等。

  1. def enumerate_func():

  2. names = ['lily','wenwen','tom']

  3. for index, s in enumerate(names,start=1):

  4. print(index,s)---------------------------------------------1 lily2 wenwen3 tom

如果不指定 start 参数,则 index 从 0 开始

测试基础-Python篇 基础③

浮点数精度问题

print(0.1+0.2)----------------------0.30000000000000004

可以使用 decimal 模块解决浮点数精度问题:

  1. from decimal import Decimalprint(Decimal('0.1') + Decimal('0.2'))print(type(Decimal('0.1') + Decimal('0.2')))print(type(Decimal('0.1')))---------------------------------------------------------0.3<class 'decimal.Decimal'>

  2. <class 'decimal.Decimal'>

注意:在使用 Decimal 时要用字符串来表示数字

布尔值其实也是数字

  • 布尔类型其实是整型的子类型

  • True 和 False 这两个布尔值可以直接当做 1 和 0 来使用

  • 通过这个特点,最常用于统计总数

  1. def sum_even(numbers: list[int]):

  2. """

  3. 返回numbers中偶数的个数

  4. :param numbers: 整数列表

  5. """

  6. return sum(i % 2 == 0 for i in numbers)

不常用但特别好用的字符串方法

  • str.partition(sep) 按照切分符 sep 切分字符串,返回一个包含三个成员的元祖 (part_before, sep, part_after);若 s 不包括分隔符,则最后一个成员默认是空字符串'';

    s = 'TomAndMarry's2 = s.partition('And')print(s2)--------------------------------('Tom ', 'And', ' Marry')

  • 2.str.translate(table) 他可以按规则一次性替换多个字符,使用它比调用多次 replace 方法更快也更简单;

    s = '明明是中文,却使用了英文标点.'table = s.maketrans(',.', ',。')s2 = s.translate(table)print(s2)-----------------------------------------------明明是中文,却使用了英文标点。

使用枚举类型来替代字面量

  • 更易读:所有人都不需要记忆某个数字代表什么;

  • 更健壮:降低输错数字或字母产生 bug 的可能性;

  1. # 用户每日奖励积分数量DAILY_POINTS_REWARDS = 100# VIP用户额外奖励20VIP_EXTRA_POINTS = 20from enum import Enumclass UserType(int, Enum):

  2. # VIP用户 VIP = 3

  3. # 小黑屋用户 BANNED = 13def add_daily_points(user):

  4. """用户每天第一次登录增加积分"""

  5. if user.type == UserType.BANNED:

  6. return

  7. if user.type == UserType.VIP:

  8. user.points += DAILY_POINTS_REWARDS + VIP_EXTRA_POINTS

  9. return

  10. user.points += DAILY_POINTS_REWARDS

  11. return

生成器

  • 定义一个生成器需要生成器函数和 yield 关键字

  • yield 和 return 最大的区别在于,return 会一次性返回结果,使用它会直接中断函数执行,而 yield 可以逐步给调用方生成结果

  • 使用生成器的优点是它们占用的内存比列表要少,因为它们只生成一个元素并在需要时生成下一个元素。这使得生成器特别适合于处理大量数据

  • 每次调用生成器函数都会生成一个新的生成器对象

  1. fruits = {'apple','orange','pineapple'}def batch(item):

  2. for _ in item:

  3. yield _print(next(batch(fruits)))print(next(batch(fruits)))print(next(batch(fruits)))---------------------------------------appleappleapple

因为每次调用生成器函数都会生成一个新的生成器对象,所以以上程序运行结果会输出三个 apple

  1. fruits = {'apple','orange','pineapple'}def batch(item):

  2. for _ in item:

  3. yield _g = batch(fruits)print(next(g))print(next(g))print(next(g))-------------------------------------------------pineappleappleorange

以上代码再次验证了'每次调用生成器函数都会生成一个新的生成器对象'结论

  • 使用生成器的 next() 函数可以在需要时单独生成生成器中的元素,而不是一次性生成整个列表。如果生成器中没有元素,则会引发 StopIteration 异常

  • 用生成器替代列表

  1. def batch_process(item):

  2. result = []

  3. for i in item:

  4. # process_item = ..处理item result.append(process_item)

  5. return result# 以上方法会有一个问题,当item过大时,会导致函数执行很耗时,并且若调用方想在某个process_item达到条件时中断,以上方法也是做不到的。所以可以使用生成器函数替代。def batch_process_2(item):

  6. for i in item:

  7. # process_item = ..处理item yield process_item# 调用方for processed_item in batch_process_2(items):

  8. # 如果某个处理对象过期了,就中断当前的所有处理 if processed_item.has_expired():

  9. break

面向对象编程

内置类方法装饰器
  • 类方法

    1.用 def 在类里定义一个函数时,这个函数通常被称作方法。调用这个方法需要先创建一个类实例;

    2.可以使用*@* classmethod装饰器定义类方法,它属于类,无需实例化也能调用;

    3.作为一种特殊方法,类方法最常见的使用场景,就是定义工厂方法来生成新实例,类方法的主角是类型本身,当发现某个行为不属于实例,而是属于整个类型是,可以考虑使用类方法;

  • 静态方法

    1.如果发现某个方法不需要使用当前实例里的任何内容,那可以使用*@* staticmethod来定义一个静态方法;

    2.和普通方法相比,静态方法不需要访问实例的任何状态,是一种与状态无关的方法,因此静态方法其实可以写成脱离于类的外部普通函数;

    2.1.如果静态方法特别通用,与类关系不大,那么把他改成普通函数会更好;

    2.2.如果静态方法与类关系密切,那么用静态方法更好;

    2.3.相比函数,静态方法有一些先天优势,比如能被子类继承和重写;

  • 属性装饰器

    1.@property 装饰器模糊了属性和方法间的界限,使用它,可以把方法通过属性的方式暴露出来;

    2.@property 除了可以定义属性的读取逻辑外,还支持自定义写入和删除逻辑;

  1. class FilePath:

  2. @property

  3. def basename(self):

  4. ....

  5. @property.setter

  6. def basename(self, name):

  7. ....

  8. @property.deleter

  9. def basename(self):

  10. ....

经过*@* property的装饰以后,basename 已经从一个普通的方法变成了 property 对象,所以可以使用 basename.setter 和 basename.deleter 方法;

定义 setter 方法,该方法会在对属性赋值是被调用;

定义 deleter 方法,该方法会在删除属性时被调用;

鸭子类型及其局限性
  • 在鸭子类型编程风格下,如果想操作某个对象,你不会去判断他是否属于某种类型,而会直接判断他是不是有你需要的方法 (或属性)。或者更激进一些。你甚至会直接尝试调用需要的方法,假如失败了,那就让她报错好了;

  • 鸭子类型的优点就是编写简单,使用灵活;

  • 鸭子类型的缺点就是缺乏标准、过于隐式;

  • 可以使用类型注解、静态检查 (mypy)、抽象类来补充鸭子类型;

抽象类
  • isinstance() 函数

    利用 isinstance() 函数,我们可以判断对象是否属于特定类型;

    isinstance() 函数能理解类之间的继承关系,因此子类的实例同样可以通过基类的校验;

  • 校验对象是否是 Iterable 类型

    在 collections.abc 模块中,有许多和容器相关的抽象类,比如代表集合的 Set、代表序列的 Sequence 等,其中有一个最简单的抽象类:Iterable,他表示的是可迭代类型;

  • 鸭子类型和抽象类总结

    鸭子类型是一种编码风格,在这种风格下,代码只关心对象的行为,不关心对象的类型;

    鸭子类型降低了类型校验的成本,让代码变得更灵活;

    传统的鸭子类型里,各种对象接口和协议都是隐式的,没有统一的显示标准;

    传统的 isinstance() 类型检查和鸭子类型的理念是相违背的;

    抽象类是一种特殊的类,他可以通过钩子方法来定制动态的子类检查行为;

    因为抽象类的定制子类化特征,isinstance() 也变得更灵活、更契合鸭子类型了;

    使用*@* abstractmethod装饰器,抽象类可以强制要求子类在继承时重写特定方法;

    除了抽象方法外,抽象类也可以实现普通的基础方法,供子类继承使用;

    在 collections.abc 模块中,有许多与容器相关的抽象类;

多重继承于MRO
  • Python 里的一个类可以同时继承多个父类;

  • 调用类的 mro() 方法,可以看到按 MRO 算法排好序的基类列表;

  • 在许多人印象中。super() 是一个用来调用父类方法的工具函数。但这么说并不准确,super() 使用的其实不是当前类的父类,而是当前类在 MRO 链条上的上一个类;

  • 应该避免多重继承;

学习建议

对于Python入门及进阶,我推荐两本我认为值得多次阅读的书籍:

  • 《Python编程从入门到实践(第二版)》- 第一部分为基础语法部分,建议刚接触 Python 的同学多次阅读并实践,夯实基础利器!

  • 《Python工匠》- 整本无尿点,强烈建议多次阅读并实践,是Python进阶的不二之选!

其他琐碎但十分实用的知识点

  • for......else......的执行顺序:

    当迭代对象完成所有迭代后且此时的迭代对象为空时,如果存在 else 子句则执行 else 子句,没有则继续执行后续代码;如果迭代对象因为某种原因(如带有 break 关键字)提前退出迭代,则 else 子句不会被执行,程序将会直接跳过 else 子句继续执行后续代码;

  • 数值型比较不能使用 not in,因为 not in 本质是循环遍历右侧数据,用左侧数据进行比对,len() in range(1,5) 可以使用,因为 range 是一个集合,可以遍历, "li" in "lili"不建议使用,因为返回结果为 True(包含),达不到预期结果,所以准确比较建议使用'==';

  • 字典取值:有两种方式,a={'name':'lili'}

    第一种:a['name']

    第二种:a.get('name')

    区别:a['wenwen'] 报错-KeyError a.get('wenwen') 不报错-None

  • 如果在方法中给全局变量赋值,则要在方法中提前声明全局变量-global;

  • 列表转成字符串''.join(list)

    用''中的字符串作为连接,拼接 list 列表中的每个元素 --- 只能用在每个元素都是字符串的时候可以用,要不然就会报错;

  • 集合数据类型 set 取值

    因为集合(set)是一种无序的不重复的元素的集合。因为集合中的元素没有特定的顺序,所以无法通过下标索引来访问。

    可以使用循环遍历取值,也可使用 in 判断目标元素是否在集合中。

  • 当遇到复杂计算的数字字面量时,保留整个数学公式,提示可读性也不会降低性能;

  • 要判断某个容器是否包含特定成员,用集合比用列表更合适,因为集合底层使用了哈希表数据结构

  1. # 列表数据越多效果越明显VALID_NAMES = ['pip', 'lili', 'name']VALID_NAMES_SET = set(VALID_NAMES)def validate_name(name):

  2. if name not in VALID_NAMES_SET:

  3. raise ValueError(f'{name} is not a valid name')

  • 使用集合去重会导致去重后的集合丢失原有的成员顺序,若要去重,又要保持原有的成员顺序可使用有序字典 OrderedDict
  1. nums = [10, 2, 3, 21, 10, 3]def ordered_dict(member: list[int]):

  2. from collections import OrderedDict

  3. result = list(OrderedDict.fromkeys(member).keys())

  4. return resultprint(ordered_dict(nums))----------------------------------------------------[10, 2, 3, 21]

  • 在遍历时不要直接修改原列表,可以启用一个新列表来保存修改后的成员;

  • 对于未来可能会变动的多返回值函数来说,可以使用 NamedTuple 类型对返回结果进行建模,可以减少后期代码变动对已有程序的影响

  1. from typing import NamedTupleclass Address(NamedTuple):

  2. """地址信息结果"""

  3. country: str

  4. province: str

  5. city: strdef latlon_to_address(lat, lon):

  6. return Address(

  7. country = country,

  8. province= province,

  9. city = city,

  10. )addr = latlon_to_address(lat, lon)# 通过属性名来使用addr

  11. # addr.city / addr.country / addr.province

  • 使用 product() 扁平化多层嵌套循环 product() 接收多个可迭代对象作为参数,然后根据他们的笛卡尔积不断生成结果;

    from itertools import productprint(list(product([1,2],[3,4])))----------------------------------------[(1, 3), (1, 4), (2, 3), (2, 4)]

  1. # 常用多层嵌套循环def find_twelve(nem_list1, num_list2, num_list3):

  2. "从这三个数字列表中,寻找是否存在和为12的3个数"

  3. for num1 in num_list1:

  4. for num2 in num_list2:

  5. for num3 in num_list3:

  6. if num1 + num2 + num3 == 12:

  7. return num1, num2, num3# 使用product()扁平化多层嵌套循环from itertools import productdef find_tewlve_v2(num_list1, num_list2, num_list3):

  8. for num1, num2, num3 in product(num_list1, num_list2, num_list3):

  9. if num1 + num2 + num3 == 12:

  10. return num1, num2, num3

  • 使用 islice 实现循环内隔行处理 需求:有一个文件,隔行读取文件中的内容。
复制代码
  1. # 方法1:使用enumeratedef parse_titles(filename):

  2. """从各行数据文件中取数据"""

  3. with open(filename, 'r') as fp:

  4. for i, line in enumerate(fp):

  5. if i % 2 == 0:

  6. yield lineif __name__ == '__main__':

  7. message_generator = parse_titles('logs.txt')

  8. while True:

  9. try:

  10. print(next(message_generator))

  11. except StopIteration as e:

  12. break

但如果需求变更为每隔3行读取或者每隔4行读取,那我们按照以上的写法应该怎么筛选呢?

复制代码
  1. # 方法2:使用islicefrom itertools import islicedef parse_titles_v2(filename):

  2. """使用slice实现隔行取值"""

  3. with open(filename, 'r') as fp:

  4. for line in islice(fp, 0, None, 2): # islice(seq, start, end, step) yield lineif __name__ == '__main__':

  5. message_generator = parse_titles_v2('logs.txt')

  6. while True:

  7. try:

  8. print(next(message_generator))

  9. except StopIteration as e:

  10. break

如果需求变更为每隔3行读取或者每隔4行读取,我们只需要将 islice(seq, start, end, step) 中的 step 改成3或者4就行了

Python基础四十问

面对洋洋洒洒的知识点,我往往 "一看就会,一写就废 ",为了更有针对性的加深知识点的印象,接下来,我将以做题的形式继续总结Python系列,如果有不正确的地方,希望各位佬儿哥指正纠偏:

1.列表的增删查改?

  • l.insert(idx, value) ---指定索引位置增加

    l.append(value) ---在末尾追加

    l.extend(iterable) ---取出可迭代对象的值,追加到列表末尾

    l1 = [1,2,3,3,4,5]l1.extend([1,[2]])print(l1)--------------------------[1, 2, 3, 3, 4, 5, 1, [2]]
    
  • del l[idx] ---删除索引处元素,索引超出会报错:IndexError: list assignment index out of range

    del l ---彻底删除列表

    l.pop(idx) ---删除索引处元素,索引超出会报错:IndexError: pop index out of range

    l.pop() ---删除列表最后一个元素,列表为空会报错:IndexError: pop from empty list

    l.remove(value) ---删除列表中第一个出现 value 的元素,值不在会报错:ValueError: list.remove(x): x not in list

    l.clear() --清除列表中的所有元素

  • l[idx]

    l.count(value) ---统计列表中指定元素出现次数,指定元素不在列表中会返回:0

    l.index(value) ---返回列表中第一个指定元素的索引,指定元素不在列表中会报错:ValueError: 11 is not in list

  • l[idx] = value

2.字典的增删查改?

  • d[new_key] = value ---如果 key 已存在则是更新操作

    d.update({key: value}) ---如果 key 存在则是更新操作

    d = dict.fromkeys(keys, value) ---dict.fromkeys(keys, value) 方法用于创建一个新字典,其中包含指定的键,并将所有键的值设置为相同的值

    d.setdefault(key, default_value) ---如果 key 已存在,则返回对应的 value,若 key 不存在,则返回 default_value,并在原字典中新增键值对 key: default_value

    # 可用setdefault()统计每个单词的出现次数text = "Hello world! Hello python! Hello chatbot!"word_list = text.split()word_count = {}for word in word_list:word_count[word] = word_count.setdefault(word, 0) + 1print(word_count)--------------------------------------------------------------------------------------------{'Hello': 3, 'world!': 1, 'python!': 1, 'chatbot!': 1}
    
  • d.pop(key) ---key 不存在会报错:KeyError: 'addr'

    d.popitem() ---随机删除一个键值对,因为字典无序,所以是随机删除,字典为空则报错:KeyError: 'popitem(): dictionary is empty'

    del d[key] ---删除指定 key,若 key 不存在则报错:KeyError: 'addr'

    del d ---彻底删除字典

    d.clear ---清空字典

  • d[key] ---若 key 不存在则报错:KeyError: 'addr'

    d.get(key) ---若 key 不存在则返回 None

    d.keys() ---以列表形式返回字典的所有 key

    d.values() ---以列表的形式返回字典的所有 value

    d.items() --以列表的形式返回字典的所有键值对,每一组键值对是一组元祖

复制代码
  1. d1 = {'name': 'Tom', 'age': 25}print(d1.keys())print(type(d1.keys()))print()print(d1.values())print(type(d1.values()))print()print(d1.items())print(type(d1.items()))------------------------------------------------dict_keys(['name', 'age'])<class 'dict_keys'>

  2. dict_values(['Tom', 25])

  3. <class 'dict_values'>

  4. dict_items([('name', 'Tom'), ('age', 25)])

  5. <class 'dict_items'>

d[key] = value

d1.update(d2) ---将 d2 更新到 d1 中,相同的 key 则更改 d1 中的 value

3.元祖的增删查改

因为元祖是不可变数据类型,所以不能不能在原元祖新增

t = (1,2,'hello')t2 = (2,3,'world')print(id(t))t += t2print(t)print(id(t))-------------------------2049302192960(1, 2, 'hello', 2, 3, 'world')2049302145920

del t ---不能 del t[idx],否则报错:TypeError: 'tuple' object doesn't support item deletion

t[idx] ---idx 不能越界,否则报错:IndexError: tuple index out of range

可遍历元祖

复制代码
  1. for _ in t:

  2. print(_)

t.count(value) ---返回元祖中 value 的个数,value 不存在返回 0

t.index(value) ---返回元祖中首个 value 的索引,value 不存在则报错:ValueError: tuple.index(x): x not in tuple

元组是不可变的,因此不能修改元组中的任何元素。

4.例举Python6种基本的数据类型,并标出哪些是不可变数据类型?

整形-int-不可变、浮点型-float-不可变、字符型-str-不可变、列表-list-可变、元祖-tuple-不可变、字典-dict-可变

5.请说明循环结构和异常处理中的 else 在什么情况下会执行?

在 for.else 循环结构中,当循环提全部循环完毕后,没有 break 或者 return 的情况下,会执行 else 代码段;

在异常处理中,try 下的代码段没有出现异常的情况下,会执行 else 代码

条件分支语句用 else 来表示"否则执行某件事"

6.列举python函数定义中有哪些不同的参数类型?

1.位置参数:根据参数在函数定义中的位置来确定。

2.默认参数:在函数定义中指定的参数值。

3.关键字参数:在调用函数时指定参数名称和对应的值。

4.星号参数:在函数定义中使用来捕获剩余的参数。
5.双星号参数:在函数定义中使用
* 来捕获剩余的关键字参数。

7.python中==和is的区别?

==比较的是两个对象的值,is 比较的是两个对象的内存地址。

不能用 is 替代==,仅当你需要判断某个对象是否是 None、False、True 时,使用 is,其他情况下请使用==。

a = [1,2,3]b = [1,2,3]print(id(a))print(id(b))print(a == b)print(a is b)--------------------22782856545922278285654272TrueFalse

a = [1,2,3]b = aprint(id(a))print(id(b))print(a == b)print(a is b)---------------------20215765550722021576555072TrueTrue

额外:关于赋值或者复制后 id() 是否异同的知识点,结论:除了'='赋值,其余的 id() 都不一样,直接举例:

import copya = [1,2,3]b = ac = a.copy()d = copy.copy(a)e = copy.deepcopy(a)f = a[:]print(id(a))print(id(b))print(id(c))print(id(d))print(id(e))print(id(f))------------------192714345516819271434551681927140937408192714093715219271435578241927143558528

8.请描述global关键字在什么条件下必须被使用?

在函数局部要重新赋值全局变量之前,需要使用 global 关键字声明全局变量。

9.请说明if name == ' main ':语句的作用?

在 Python 中,当一个模块被执行时,if name == 'main ':语句块会被执行。此语句块可以用来测试模块的代码,而不会影响模块的其他功能。

如果模块被其他模块导入,则name 的值为该模块的名称,而不是main 。如果该模块是主程序,则name 的值为main ,此时该语句块会被执行。

这样的语句使得可以在模块被其他模块导入时忽略测试代码,并且只在模块被独立运行时执行测试代码。

10.面向对象编程有哪三大特性?请说明各个特性的意义。

封装:隐藏内部状态和实现细节,仅提供必要的接口给外部使用。

继承:允许创建新的对象类型,并基于现有的对象类型派生,从而继承其行为和状态。

多态:允许不同类型的对象对相同消息做出不同的响应。

11.类反射中常用的方法及含义?

常用的类反射方法有:

type(object):获取对象的类型,返回一个 type 对象。

isinstance(object, classinfo):判断对象是否是某种类型的实例,返回布尔值。

issubclass(class, classinfo):判断一个类是否是另一个类的子类,返回布尔值。

getattr(object, name[, default]):获取对象的属性或方法,如果不存在,可以返回 default 参数指定的默认值。

hasattr(object, name):判断对象是否具有某个属性或方法,返回布尔值。

setattr(object, name, value):设置对象的属性值。

delattr(object, name):删除对象的属性。

使用类反射可以动态地获取和操作类的信息,是动态语言的重要特性。

12.python中创建一个新线程有哪几种方式?

1.使用 threading 模块:通过定义一个继承自 Thread 的类并重写其 run 方法,然后通过该类的实例调用 start 方法启动线程。

2.使用 multiprocessing 模块:通过使用 Process 类创建新的进程。

3.使用协程:通过使用生成器实现协程,在协程内部通过 yield 实现非阻塞的多任务执行。

多线程编程是高并发编程的一种常见形式,可以提高程序的执行效率。

13.python中GIL全局解释器锁在什么情况下会被释放?

Python 中的 GIL (Global Interpreter Lock) 是一种机制,它限制任意时刻仅有一个线程可以运行在 Python 解释器中。GIL 在以下情况下会被释放:

解释器在执行 CPU 密集型任务时:例如运算,在这种情况下,GIL 会每隔一定时间被释放,以便其他线程有机会被调度执行。

解释器在执行 I/O 密集型任务时:例如读取文件,在这种情况下,由于 I/O 操作需要等待外部设备,所以 GIL 会在 I/O 操作期间被释放。

GIL 可能会影响多线程程序的性能,因此通常不建议在 Python 中开发 CPU 密集型的多线程程序。可以使用多进程来代替多线程以提高性能。

14.描述编写装饰器的原则是什么?

1.不改变原函数的内部逻辑

2.不改变原函数的调用方法

15.现在有一个Animal类有初始化方法定义如下:

class Animal:

def init (self, skin, legs):

self.skin = skin

self.legs = legs

如果现在想定义一个Dog类,并继承于这个Animal类,并想给这个Dog类增加一个nickname对象属性,Dog类的初始化方法应该怎么定义才能保证 Dog 类和其父类均能初始化成功?

复制代码
  1. # 两种写法,第二种以Cat举例class Animal:

  2. def __init__(self, skin, legs):

  3. self.skin = skin

  4. self.legs = legsclass Dog(Animal):

  5. def __init__(self, skin, legs, nickname):

  6. super().__init__(skin, legs)

  7. self.nickname = nicknameclass Cat(Animal):

  8. def __init__(self, skin, legs, hobby):

  9. Animal.__init__(self, skin, legs)

  10. self.hobby = hobbya = Animal(skin='sss', legs='lll')d = Dog(skin='sss', legs='lll', nickname='nnn')c = Cat(skin='sss', legs='lll', hobby='hhh')print(a.skin)print(d.nickname)print(c.hobby)print(c.skin)----------------------------------------------------------------------sssnnnhhhsss

super 方法是 Python 中的一种特殊方法,用于引用父类。它常用于多重继承,当子类需要调用父类的方法时,就可以使用 super 方法。这个方法可以直接调用父类的方法,而无需显式命名父类名称。

16.文件zen.txt中保存着python之禅,请使用python代码统计该文件中每个单词出现的次数。

复制代码
  1. file_path = r'C:\Users\EDZ\Desktop\zen.txt'with open(file_path, 'r') as f:

  2. text = f.read()words = text.split()word_counts = {}for word in words:

  3. if word in word_counts:

  4. word_counts[word] += 1

  5. else:

  6. word_counts[word] = 1print(word_counts)

17.编写一个装饰器,使用该装饰器能够显示任意函数运行所需时间。

复制代码
  1. def running_time(fun):

  2. def wrapper(*args, **kwargs):

  3. start_time = time.time()

  4. result = fun(*args, **kwargs)

  5. end_time = time.time()

  6. print(f'{fun.__name__}运行花费了:{end_time-start_time:.2f} 秒。')

  7. return result

  8. return wrapper@running_timedef take_time():

  9. time.sleep(2)take_time()----------------------------------------------------take_time运行花费了:2.01 秒。

18.用两种方法合并下面列表

x = ['a', 'b']y = ['c', 'd', 'e']x.extend(y)# 或x += y

19.计算得到列表当中长度最长的字符串words = ['Python', 'is', 'awesome']

复制代码
  1. words = ['Python', 'is', 'awesome']# 我的笨方法s = ''for _ in words:

  2. if len(_) > len(s):

  3. s = _print(s)# 标答给的方法

  4. # 使用内置函数 max() 和 len() 计算,在 max() 函数中使用 key 参数指定了用于比较大小的函数为 len(),这样比较的就是字符串的长度,而不是字典序。longest_word = max(words, key=len)print(longest_word)

20.将列表中的顺序倒转 (2 种方法) words = ['Python', 'is', 'awesome']

words = ['Python', 'is', 'awesome']# 方法1,列表的reverse()方法(改变原列表)words.reverse()print(words)# 方法2,列表切片(生成新列表,原列表不变)w = words[::-1]print(w)

21.将字典当中的键值对位置调换

staff = {'Data Scientist': 'Mike', 'Django Developer': 'Dylan'}

答:

复制代码
  1. staff = {'Data Scientist': 'Mike', 'Django Developer': 'Dylan'}# 我的笨方法reverse = {}for k, v in staff.items():

  2. reverse[v] = kprint(reverse)# 标答给的方法(字典推导式)inverted_staff = {v: k for k, v in staff.items()}print(inverted_staff)

22.将嵌套列表合并为一个列表

l = [[1, 2, 3], [4, 5], [6], [7, 8], [9]]

答:

复制代码
  1. # 针对此题目,我想到的是循环遍历result = []for i in l:

  2. for n in i:

  3. result.append(n)print(result)# 标答给的方法1:

  4. # 在 sum() 函数中使用的第二个参数是空列表,表示从空列表开始计算和。merged_list = sum(l, [])print(merged_list) # 标答给的方法2:列表推导式merged_list = [item for sublist in l for item in sublist]print(merged_list)# 可如上3个方法只能针对此题目,一旦题目列表没这么规范,比如下面的列表,那么如上3个方法就无法实现l = [0, [1, 2, [3]], [4, 5], [6], [7, 8], [9]]# 能够同时解决如上问题的方法是使用递归函数def flatten_list(l):

  5. flat_list = []

  6. for item in l:

  7. if type(item) == list:

  8. flat_list.extend(flatten_list(item))

  9. else:

  10. flat_list.append(item)

  11. return flat_listprint(flatten_list(l))

23.列表当中数据类型的转换

  • 我们要将其转换成整数类型====>['1', '2', '3']

  • 我们要将其转换成浮点数类型====>['1', 2, '3.0', 4.0, '5', 6]

答:

l = ['1', '2', '3']l1 = [int(i) for i in l]print(l1)l2 = ['1', 2, '3.0', 4.0, '5', 6]l3 = [float(i) for i in l2]print(l3)

24.将列表转化成字典

cars = ['Audi', 'BMW', 'Ford', 'Tesla', 'Volvo']

答:

cars = ['Audi', 'BMW', 'Ford', 'Tesla', 'Volvo']d = dict.fromkeys(cars, 0)print(d)

25.将列表当中的重复元素去除

['a', 'a', 'b', 'a', 'c']

答:

l = ['a', 'a', 'b', 'a', 'c']l1 = list(set(l))print(l1)

26.从列表中筛选出特定元素 (2种方法)

cars = ['Audi', 'BMW', 'Ford', 'Tesla', 'Volvo']

答:

cars = ['Audi', 'BMW', 'Ford', 'Tesla', 'Volvo']# 我想到的是列表推导式l = [i for i in cars if i == 'Volvo']print(l)# 标答使用filterl2 = filter(lambda car: car == 'Volvo', cars)print(list(l2))# filter 函数在 Python 中返回一个过滤器对象,它是一个迭代器,所以想打印值需要使用list()

27.列表中的元素排序

numbers = [55, -30, 28, -36, 48, 20]

cars = ['Ford', 'Tesla', 'BMW', 'Volvo', 'Audi']

答:

numbers.sort()print(numbers)cars.sort()print(cars)

28.合并集合

set1 = {"1", "2", "5"}

set2 = {"4", "6", "7"}

答:

set1.update(set2)print(set1)

29.根据键来对字典进行排序

d = {'one': 1, 'three': 4, 'five': 8, 'six': 10, 'two': 2}

答:

sorted_dict = sorted(d.items(), key=lambda x: x[0])print(sorted_dict)

30.根据键值来对字典进行排序

d = {'one': 1, 'three': 4, 'five': 8, 'six': 10, 'two': 2}

答:

sorted_dict = sorted(d.items(), key=lambda x: x[1])print(sorted_dict)

31.替换字符串

s = "Python is a programming language. Python is awesome"# 字符类型是不可变数据类型,str.replace()方法不会改变原字符串,会生成新值ss = s.replace('P','p')print(ss)

32.计算指定字符串出现的次数

a = 'python is a programming language. python is python.'

答:

  1. # 我得笨方法:d = {}for _ in a:

  2. if _ not in d:

  3. d[_] = 1

  4. else:

  5. d[_] += 1print(d['p'])# 标答print(a.count('p'))

33.将矩阵转置

a = [[1, 2, 3],

[4, 5, 6],

[7, 8, 9]]

答:

b = [list(s) for s in zip(*a)]print(b)

34.生成斐波那契数列

斐波那契数列是一个数列,其中的每个数都是前两个数的和。

答:

  1. def fibonacci(n):

  2. if n <= 0:

  3. return []

  4. elif n == 1:

  5. return [0, ]

  6. elif n == 2:

  7. return [0, 1]

  8. else:

  9. fib = [0, 1]

  10. for i in range(2, n):

  11. fib.append(fib[-1] + fib[-2])

  12. return fibprint(fibonacci(10))-----------------------------------------------------[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

35.冒泡排序

复制代码
  1. def bubble(l):

  2. for i in range(len(l) - 1):

  3. for j in range(len(l) - 1 - i):

  4. if l[j] > l[j + 1]:

  5. l[j], l[j + 1] = l[j + 1], l[j]

  6. return l

36.Python的解包是什么?

解包是 Python 里的一种特殊赋值语句,可以把可迭代对象 (列表,元祖,字典,字符串) 一次性赋给多个值。

a, b, c = (1, 2, 3)

a, b = b, a
复制代码
  1. numbers = [1, 2, 3, 4, 5]for a, b in zip(numbers, numbers[1:]):

  2. print(a, b)---------------------------------------------------------1 22 33 44 5

注意:

  • 普通变量解包,需要注意变量数量和列表中元素数量应保持一致,否则报'SyntaxError: cannot assign to literal';

  • 如果可迭代对象是字典,则变量个数要等于字典中的键值对个数,若不指定字典的取值,则默认取字典的 key 值,若指定字典的值为 items(),则变量为字典键值对的元组形式;

37.有一个key为姓名,value为年龄的字典,根据年龄正序排列姓名,并输出姓名列表,若没有年龄,则放在最后;

users = {'tom': 19, 'jerry': 13, 'jack': None, 'andrew': 43}

答:

知识点:在排序前将年龄为 None 的值变更为正无穷大;

  • 正无穷:float("inf")

  • 负无穷:float("-inf")

复制代码
  1. # 我想到的方法:

  2. # 先将字典中年龄为None的值变更成正无穷大def key_func(users):

  3. for key in users.keys():

  4. if users[key] is None:

  5. users[key] = float('inf')# 根据年龄进行正序排序,最后以列表形式输入排序好的姓名def sort_user(user: dict):

  6. sort_item_for_v = sorted(user.items(), key=lambda x: x[1])

  7. return [user[0] for user in sort_item_for_v]key_func(users)print(sort_user(users))-------------------------------------------------------------------------------['jerry', 'tom', 'andrew', 'jack']

复制代码
  1. # 参考答案:def sort_user_inf(users: dict):

  2. """

  3. 接收一个key为姓名,value为年龄的字典,根据年龄正序排列姓名,若没有年龄,则放在最后

  4. :param users: 用户名:年龄字典

  5. :return: 返回姓名列表

  6. """

  7. def key_func(username):

  8. age = users[username]

  9. # 当年龄为空时,返回正无穷大作为key,因此就会被排到最后 return age if age is not None else float('inf')

  10. return sorted(users.keys(), key=key_func)print(sort_user_inf(users))-----------------------------------------------------------------------------['jerry', 'tom', 'andrew', 'jack']

38.合并字典的多种方式?

  • 方式 1:update

    d1 = {'name': 'Lili', 'score': 90}d2 = {'name': 'Tom', 'hobby': 'run'}d1.update(d2)print(d1)-----------------------------{'name': 'Tom', 'score': 90, 'hobby': 'run'}# 这种方法会改变d1的原始值

  • 方式 2:编写一个函数 (不改变 d1 的原始值)

  1. d1 = {'name': 'Lili', 'score': 90}d2 = {'name': 'Tom', 'hobby': 'run'}def update_dict(d1: dict, d2: dict):

  2. d = d1.copy()

  3. d.update(d2)

  4. return dprint(update_dict(d1,d2))print(d1)print(d2)---------------------------------------{'name': 'Tom', 'score': 90, 'hobby': 'run'}{'name': 'Lili', 'score': 90}{'name': 'Tom', 'hobby': 'run'}

  • 方式 3:解包

    d1 = {'name': 'Lili', 'score': 90}d2 = {'name': 'Tom', 'hobby': 'run'}print({**d1, **d2})print({**d2, **d1})print(d1)print(d2)--------------------------------------{'name': 'Tom', 'score': 90, 'hobby': 'run'}{'name': 'Lili', 'hobby': 'run', 'score': 90}{'name': 'Lili', 'score': 90}{'name': 'Tom', 'hobby': 'run'}

  • 方式 4:Python3.9 版本后可用"|"合并字典

    d1 = {'name': 'Lili', 'score': 90}d2 = {'name': 'Tom', 'hobby': 'run'}print(d1|d2)print(d2|d1)print(d1)print(d2)-----------------------------{'name': 'Tom', 'score': 90, 'hobby': 'run'}{'name': 'Lili', 'hobby': 'run', 'score': 90}{'name': 'Lili', 'score': 90}{'name': 'Tom', 'hobby': 'run'}

39.json和Python中的dict有什么区别?

  • 1.JSON 的类型是字符串,字典的类型是 dict;

  • 2.JSON 的 key 只能是字符串,字典的 key 可以是任何可 hash 对象,如:字符串,数字,元祖;

  • 3.JSON 的 key 是有序的,可以重复的;字典的 key 不能重复;

  • 4.JSON 的 key 有默认值 undefined,字典的 key 默认没有默认值;

  • 5.JSON 的 value 可以是字符串、浮点数、布尔值、null 或者他们组成的数组或对象,字典的 value 可以是任意类型的对象;

  • 6.JSON 的 value 访问方式可以是 [] 或者.,字典的 value 访问方式只能是 key 值;

  • 7.JSON 的字符串强制使用双引号,字典的字符串可以是单引号也可以是双引号;

  • 8.字典可以嵌套元祖,JSON 只有数组;

  • 9.真假空的表示:JSON(true,false,null),字典(True,False,None);

  • 10.JSON 的中文必须是 Unicode 编码,如"\u6211"。

40.Python列表和字符串的相互转换?

第一种类型:

s = '1,2,3,4,5'l = s.split(',')print(l)l2 = [int(i) for i in l]print(l2)--------------------['1', '2', '3', '4', '5'][1, 2, 3, 4, 5]

第二种类型:

l1 = ['1','2','3']s1 = ','.join(l1)print(s1)---------------1,2,3

第三种类型:

l2 = [1,2,3]s2 = ','.join([str(i) for i in l2])print(s2)-----------------------------1,2,3

行动吧,在路上总比一直观望的要好,未来的你肯定会感 谢现在拼搏的自己!如果想学习提升找不到资料,没人答疑解惑时,请及时加入扣群: 320231853,里面有各种软件测试+开发资料和技术可以一起交流学习哦。

最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:

这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!

相关推荐
数据小爬虫@2 分钟前
如何利用java爬虫获得淘宝商品评论
java·开发语言·爬虫
qq_1728055910 分钟前
RUST学习教程-安装教程
开发语言·学习·rust·安装
wjs202417 分钟前
MongoDB 更新集合名
开发语言
monkey_meng21 分钟前
【遵守孤儿规则的External trait pattern】
开发语言·后端·rust
legend_jz1 小时前
【Linux】线程控制
linux·服务器·开发语言·c++·笔记·学习·学习方法
drebander1 小时前
使用 Java Stream 优雅实现List 转化为Map<key,Map<key,value>>
java·python·list
tangliang_cn1 小时前
java入门 自定义springboot starter
java·开发语言·spring boot
程序猿阿伟1 小时前
《智能指针频繁创建销毁:程序性能的“隐形杀手”》
java·开发语言·前端
新知图书1 小时前
Rust编程与项目实战-模块std::thread(之一)
开发语言·后端·rust
威威猫的栗子1 小时前
Python Turtle召唤童年:喜羊羊与灰太狼之懒羊羊绘画
开发语言·python