测试基础 测试基础-Python 篇 基础①

耿晓 · 2023年02月14日 · 最后由 Acar 回复于 2023年03月27日 · 5116 次阅读

再梳理一遍 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 之后,可以使用类型注解功能来注明变量类型,在变量后添加类型,并用冒号隔开;

def repeat_message(message: str, count: int) -> str:
    return message * count

算术运算符

  • // 取整除
  • % 取余
  • ** 幂

不同类型变量之间的计算

  • 数字型变量之间可以直接计算;
  • 如果变量是 bool 型,在计算时,true 对应的是 1,false 对应的是 0;
  • 字符串变量之间使用 + 拼接字符串;

获取输入的信息-input

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

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

格式化输出

  • %s --字符串
  • %d --有符号十进制整数,%06d 表示输出的整数显示位数,不足的地方使用 0 补全
  • %f --浮点数,%.2f 表示小数点后只显示两位,会四舍五入
  • %% --输出%
vb1 = 'Tom'
print("hello %s" % vb1)

vb2 = 5
print('有符号十进制整数:%d' % vb2)
print('输出显示位数的整数:%06d' % vb2)

vb3 = 3.1415926
print('保留两位小数:%.2f' % vb3)
print('保留三位小数:%.3f' % vb3)

vb4 = 80
print('正确率为:%d%%' % vb4)

--------------------------------------------------------------------
hello Tom
有符号十进制整数5
输出显示位数的整数000005
保留两位小数3.14
保留三位小数3.142
正确率为80%

逻辑运算

  • and:
    条件 1 and 条件 2

  • or:
    条件 1 or 条件 2

  • not:(取反)
    not 条件

    a = 10
    b = 20
    c = 10
    if c == a and c == b:
    print('right')
    else:
    print('error')
    -------------------------------
    error
    
    a = 10
    b = 20
    c = 10
    if 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。

    from collections import OrderedDict
    d = OrderedDict()
    d['one'] = 1
    d['two'] = 2
    print(d)
————————————————————
    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 开始)
  • 切片索引:[start🔚step]
  • 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 方式
# 将username靠右对其,左侧补空格一共到20位
username = 'Lili'
print(f'{username:>20}')
-------------------------------------
                Lili
  • 对参数复用时可以使用 str.format 方式
username = 'Lily'
sore = 10
print('{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))
--------------------------------------------------
True
False

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+;

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

    with open('user.txt', 'a+') as f:
        # 将文件指针重置至开始位置(这样就不会导致f.readlines()读不到数据了)
        f.seek(0)
        # 返回文件指针位置
        print(f.tell())
    
  • with 是 python 中的上下文管理器,它会自动帮你管理文件的句柄

    with open(r'D:\testlog.txt') as f:
    for line in f.readlines():
        print(line,end='')
    
  • 文件与文件夹
    windows 文件路径用反斜线,Linux 文件路径用正斜线,要想将程序在不同系统上运行,则可用 os.path.join() 方法;

    myFiles = ['accounts.txt','details.csv','invite.docx']
    for filename in myFiles:
        print(os.path.join('c:\\User\\asweigart',filename))
-----------------------------------------------------------------------------------------
c:\User\asweigart\accounts.txt
c:\User\asweigart\details.csv
c:\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()
    
  • 设置守护线程
    主线程结束后立即结束所有设置为守护线程的子线程;

  • 多线程锁

    import threading
    balance = 0
    lock = threading.RLock()
    def change_it(n):
    lock.acquire()
    try:
        global balance
        balance += n
        balance -= n
    finally:
        lock.release()
    def run_threading(n):
    for i in range(100000000):
        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'

额外:
我在学习中,发现正则表达式在任何语言中都占有很大部分的占比,但正则表达式相关的知识点又过于零碎,对于榆木脑袋的我真是学一遍忘一遍。在实际工作中,我自己真正用到正则的地方并不多,再看同事,目前就发现前端同学有可能会用到正则去做一些事情,并且用到的时候都是度娘,一是自己真记不住,二是度娘 copy 过来的多数情况是比自己写要严谨的多的。基于此,我把正则视为投入产出比太低的事情,仅需要记住个大概印象,真到用时能分清度娘上哪个轮子能用哪个轮子用不了就可以了。

测试基础-Python 篇 基础②

共收到 2 条回复 时间 点赞

补充一下 Python 项目目录和文件的命名规范,建议来源于 ChatGPT。

基础篇 感觉好全面 ,很适合我这种小白!!!

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册