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

news2024/11/18 13:50:32

测试基础-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,里面有各种软件测试+开发资料和技术可以一起交流学习哦。

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1713222.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

21天精通FL Studio21.2.8!中文汉化全攻略方法教程

在音乐制作的世界中&#xff0c;有一款软件以其强大的功能和易用性而广受好评&#xff0c;那就是FL Studio。而最新版本的FL Studio 21更是在原有的基础上进行了全面的升级&#xff0c;为我们带来了更多的惊喜。今天&#xff0c;我们就一起来了解一下这款最新的水果软件——FL …

全球首例光伏电场网络攻击事件曝光

快速增长的光伏发电正面临日益严重的网络安全威胁。近日&#xff0c;日媒报道了首个针对光伏电场的网络攻击事件。 首例公开确认的光伏电网攻击 日本媒体《产经新闻》近日报道&#xff0c;黑客劫持了一个大型光伏电网中的800台远程监控设备(由工控电子制造商Contec生产的Solar…

超分论文走读

codeFormer 原始动机 高度不确定性&#xff0c;模糊到高清&#xff0c;存在一对多的映射纹理细节丢失人脸身份信息丢失 模型实现 训练VQGAN 从而得到HQ码本空间作为本文的离散人脸先验。为了降低LQ-HQ映射之间的不确定性&#xff0c;我们设计尽量小的码本空间和尽量短的Code…

文心智能体:基于零代码平台的智能体开发与应用

文章目录 初识文心智能体文心智能体平台优势文心智能体平台功能 创建文心智能体总结 初识文心智能体 文心智能体平台是基于文心大模型的智能体构建平台&#xff0c;为开发者提供低成本的开发方式&#xff0c;支持广大开发者根据自身行业领域、应用场景&#xff0c;采用多样化的…

isscc2024 short course4 In-memory Computing Architectures

新兴的ML加速器方法&#xff1a;内存计算架构 1. 概述 内存计算&#xff08;In-memory Computing&#xff09;架构是一种新兴的机器学习加速器方法&#xff0c;通过将计算能力集成到存储器中&#xff0c;以减少数据移动的延迟和能耗&#xff0c;从而提高计算效率和性能。这种方…

用于癌症免疫治疗的自佐剂聚胍纳米疫苗

近期&#xff0c;沈阳药科大学孙进教授团队、罗聪教授团队与新加坡国立大学陈小元教授团队共同合作在美国化学会旗下期刊《ACS nano》&#xff08;IF17.1&#xff09;上发表题为“Self-Adjuvanting Polyguanidine Nanovaccines for Cancer Immunotherapy”&#xff08;用于癌症…

Sora,开启通往世界模拟之路!

2024年2月16日&#xff0c;OpenAI发布视频生成AI大模型Sora。消息一经发出&#xff0c;业界再一次被之震撼。 OpenAI官网描述&#xff1a;Sora是一个根据文本指令生成真实与虚拟场景的AI模型&#xff0c;可根据用户指令生成时长达1分钟的高清视频&#xff0c;能生成具有多个角色…

ee trade:主力如何建仓吸筹的

主力建仓吸筹是指大型机构投资者或市场主力在股票市场中通过一系列策略和操作&#xff0c;逐步购买并积累大量股票&#xff0c;以建立或增加其在某只股票上的持仓。这个过程通常是为了在未来通过股价上涨来实现盈利。以下是一些主力可能采用的建仓吸筹策略&#xff1a; 隐蔽吸…

命运方舟 失落的方舟台服下载教程+账号注册教程(图文全攻略)

命运方舟 失落的方舟台服下载教程账号注册教程(图文全攻略) 失落的方舟&#xff0c;作为今年一款备受瞩目的MMORPG类型游戏&#xff0c;在官宣的时候就收获了一波不小的热度。这款游戏由游戏开发商Smile gate开发&#xff0c;游戏本体搭建于知名的虚幻引擎之上&#xff0c;为玩…

torch.scatter看图理解

torch.Tensor.scatter 有 4 个参数&#xff1a; scatter(dim, index, src, reduceNone) 先忽略 Reduce&#xff0c;最后再解释。先从最简单的开始。我们有一个 (2,4) 形状的张量&#xff0c;里面填充了 1&#xff1a; 粉红色的符号表示张量结构 并且我们传入相应的参数并得到…

5.25.6 深度学习在放射图像中检测和分类乳腺癌病变

计算机辅助诊断 (CAD) 系统使用数字化乳房 X 线摄影图像并识别乳房中存在的异常情况。深度学习方法从有限数量的专家注释数据中学习图像特征并预测必要的对象。卷积神经网络&#xff08;CNN&#xff09;在图像检测、识别和分类等各种图像分析任务中的性能近年来表现出色。本文提…

用易查分制作研学活动报名,支持在线签名,一键导出报名统计表格!

学校组织研学活动时&#xff0c;需要家长扫码在线填写报名信息&#xff0c;确认安全承诺和手写签名&#xff0c;提交报名后希望分配报名号&#xff0c;应该如何实现&#xff1f; 易查分的新建填表功能就可以实现上述需求&#xff0c;下面就来教大家如何制作吧。 &#x1f4cc;使…

常用IP核的引脚图

一、复数乘法 这是一个Xilinx&#xff08;赛灵思&#xff09;的复数乘法IP核的接口图&#xff0c;包含了几个主要的AXI-Stream接口。每个接口都有其特定的用途&#xff0c;下面将详细解释各个引脚的作用。 主要接口和引脚说明 S_AXIS_A&#xff08;输入复数A&#xff09; s…

【网络安全】新的恶意软件:无文件恶意软件GhostHook正在广泛传播

文章目录 推荐阅读 一种新的恶意软件 GhostHook v1.0 正在一个网络犯罪论坛上迅速传播。这种创新的无文件浏览器恶意软件由 Native-One 黑客组织开发&#xff0c;具有独特的分发方式和多功能性&#xff0c;对各种平台和浏览器构成重大威胁。 GhostHook v1.0 支持 Windows、Andr…

一个交易者的自白:念念不忘的交易,10个日内9个亏

一、新手: 面对爆仓,我像个白痴 我是在2012年开始接触的&#xff0c;这些年里我尝到了残酷失败的滋味&#xff0c;更品尝过胜利带来的喜悦。刚刚接触时很自信&#xff0c;总想着自己有一天一定会变成千万富翁的&#xff0c;用杠杆获取暴利。 在我首次爆仓的时候&#xff0c;我的…

QT6.2.4 MSVC2019 连接MySql数据库,无驱动问题

1.下载 查询一下数据库驱动 qDebug()<<QSqlDatabase::drivers(); 结果显示&#xff0c;没有QMYSQL的驱动。 QList("QSQLITE", "QMARIADB", "QODBC", "QPSQL") MySql6.2.4驱动下载地址&#xff0c;如果是别的版本&#xff0c;…

使用Python构建CART决策树回归模型

数据预处理 此次构建模型是根据泰坦迪克号邮轮票价、乘客性别、船上亲友数量等特征信息来预测乘客存活率的模型&#xff0c;使用的数据集为泰坦尼克数据集&#xff0c;下载地址&#xff1a;taitanic | Kaggle。 在下载完数据集后&#xff0c;可以先试用 ydata_profiling库&am…

Codeforces Round 946 (Div. 3) A~G

A.Phone Desktop (枚举) 题意&#xff1a; 小 A A A的手机有一个桌面&#xff08;或称启动器&#xff09;。桌面可以由多个屏幕组成。每个屏幕表示为大小为 5 3 5 \times 3 53 的网格&#xff0c;即五行三列。 有 x x x 个应用程序的图标大小为 1 1 1 \times 1 11 个单…

高铁Wifi是如何接入的?

使用PC端的朋友&#xff0c;请将页面缩小到最小比例&#xff0c;阅读最佳&#xff01; 在飞驰的高铁上&#xff0c;除了窗外一闪而过的风景&#xff0c;你是否好奇过&#xff0c;高铁Wifi信号如何连接的呢&#xff1f; 远动的火车可不能连接光纤吧&#xff0c;难道是连接的卫星…

6.2 Go 切片(Slice)

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…