自动化测试——Python基础

文章目录

  • 前言
  • 一、Python的基础语法
    • 1.标识符
    • 2.注释
  • 二、Python中常见的数据类型
    • 1.Number(数字)
      • 1.1.int(整数数据类型)
      • 1.2.float(浮点型)
      • 1.3.bool(布尔类型)
    • 2.String(字符串)
    • 3.List(列表)
    • 4.Tuple(元组)
    • 5.Set(集合)
    • 6.Dictionary(字典)
  • 三、输入和输出
    • 1.读取键盘输入
    • 2.格式化输出
  • 四、数据类型转换
  • 五、运算符
    • 1.算术运算符
    • 2.比较(关系)运算符
    • 3.赋值运算符
    • 4.逻辑运算符
    • 5.位运算符
    • 6.成员运算符
    • 7.身份运算符
    • 8.运算符优先级
  • 六、Python常见数据类型具体操作方法
    • 1.字符串常用的操作方法
    • 2.列表常用的操作方法
    • 3.元组常用的操作方法
    • 4.字典常用的操作方法
    • 5.集合常用的操作方法
    • 6.列表、元组、集合的相互转化
  • 七、Python中的可变数据类型与不可变数据类型
  • 八、浅拷贝与深拷贝
    • 1.浅拷贝
    • 2.深拷贝
    • 3.总结
  • 九、流程控制
    • 1.if分支语句
    • 2.关键字match与case
    • 3.三目运算符
    • 4.循环
      • 4.1.for循环
      • 4.2.while循环
      • 4.3.循环中的关键字break与continue
  • 十、函数
    • 1.函数的定义与调用
    • 2.指定形参和返回值的类型
    • 3.关键字参数
    • 4.默认参数
    • 5.不定长参数
      • 5.1.不定长位置参数*args
      • 5.2不定长关键字参数**kwargs
    • 6.函数的局部变量与全局变量
    • 7.匿名函数
    • 8.函数闭包
  • 十一、模块与包的使用
  • 十二、Python异常处理
  • 十三、文件常用操作
    • 1.常见的文件类型
    • 2.文件的属性
    • 3.文件的读写模式
      • 3.1.读
      • 3.2.写
      • 3.3.读写模式总结
    • 4.文件的常用操作
    • 5.案例(删除一个非空的文件夹)
  • 十四、面向对象
    • 1.面向对象技术简介
    • 2.封装
      • 1.1.类的实例属性定义和实例方法定义
      • 1.2.实例属性和实例方法的使用
      • 1.3.自定义实例属性
      • 1.4.类属性和类方法的定义
      • 1.5.类属性和类方法的使用
      • 1.5.静态方法的定义及使用
    • 3.继承
      • 3.1.单继承的使用
      • 3.2.多继承的使用
      • 3.3.子类调用父类同名属性和方法
    • 4.多态
    • 5.数据类装饰器
  • 十五、装饰器
    • 1.装饰器的定义
    • 2.装饰器的语法糖使用
    • 3.装饰器的使用场景
    • 4.带有参数的装饰器
    • 5.带有参数的装饰器
  • 十六、生成器反射
  • 十七、反射
    • 1.通过反射添加或覆盖对象方法
    • 2.通过反射删除
    • 3.通过反射判断是否存在指定的方法
    • 4.通过反射读取方法
  • 十八、第三方库
  • 1.自动化测试使用的第三方库
  • 2.第三方库的安装、卸载、查看
  • 3.虚拟环境和本地环境的区分

前言

本篇文章内容基于Python 3.10.6版本解释器

一、Python的基础语法

1.标识符

  • 标识符的定义:变量名,函数名,类名,对象名等等的统称(Python中所有的命名都叫做标识符)
  • 标识符的命名规则:
    • 第一个字符必须是字母表中字母或下划线 _
    • 标识符的其他的部分由字母、数字和下划线组成
    • 标识符不能是关键字
    • 标识符对大小写敏感(区分大小写)
  • 标识符命名建议:
    • 见名知意:尽量使用英文单词进行命名,比如名字:name,年龄:age
    • 小驼峰命名法则:第一个单词以小写开始,第二个单词以大写开头:myName
    • 大驼峰命名法则:每个单词的首字母都大写:FirstName
    • 下划线命名法则:user_name

2.注释

  • 注释核心作用:

    • 让人可以看得懂代码的作用,增加代码的可读性
    • 让不想执行的代码直接注释掉,那么就不会参与程序的运行
  • 单行注释:Python中单行注释以 # 开头

    # 这是一个单行注释
    
  • 多行注释:多行注释可以用多个 # 号,还有 '''"""

    # 这是第一行注释
    # 这是第二行注释
    
    '''
    这是多行注释
    第一行
    第二行
    '''
    
    """
    这是多行注释
    第一行
    第二行
    """
    

二、Python中常见的数据类型


列表和元组可以存放Python中任意的数据类型

  • 不可变数据类型:Number(数字)、String(字符串)、Tuple(元组);
  • 可变数据类型:List(列表)、Dictionary(字典)、Set(集合)
  • 数据类型归类:
    • 容器类型:字符串,列表,元组,字典,集合
    • 数字类型:整型,浮点型,布尔类型

1.Number(数字)

1.1.int(整数数据类型)

# 整型(int)
number = 666
print(type(number))  # <class 'int'>

1.2.float(浮点型)

# 浮点型(float)
number = 3.14
print(type(number))  # <class 'float'>

1.3.bool(布尔类型)

  • 布尔类型特点:

    • 布尔类型只有两个值:TrueFalse
    • 布尔类型可以和其他数据类型进行比较,比如数字、字符串等。在比较时,Python 会将 True 视为 1,False 视为 0
    • 布尔类型可以和逻辑运算符一起使用,包括 and、or 和 not。这些运算符可以用来组合多个布尔表达式,生成一个新的布尔值
    • 布尔类型也可以被转换成其他数据类型,比如整数、浮点数和字符串。在转换时,True 会被转换成 1,False 会被转换成 0
    # bool(布尔类型)
    bool1 = True
    bool2 = False
    print(type(bool1))  # <class 'bool'>
    print(type(bool2))  # <class 'bool'>
    

注意:在Python中,所有非零的数字和非空的字符串、列表、元组等数据类型都被视为 True,只有 0、空字符串、空列表、空元组等被视为 False。因此,在进行布尔类型转换时,需要注意数据类型的真假性

2.String(字符串)

  • Python中的字符串用单引号 '' 或双引号 "" 或三引号 '''''' 括起来

    # str(字符串)
    str1 = '666'
    str2 = "张三"
    str3 = '''李四'''
    print(type(str1))  # <class 'str'>
    print(type(str2))  # <class 'str'>
    print(type(str3))  # <class 'str'>
    

3.List(列表)

  • 列表:[] 表示列表。列表当中可以存放Python中任意的数据类型

    # list(列表)
    list1 = [1, "张三", 3.14, True]
    print(type(list1))  # <class 'list'>
    

4.Tuple(元组)

  • 元组:元组写在小括号() 里,元素之间用逗号隔开。元组与列表类似,不同之处在于元组的元素不能修改

  • 元组的括号可以省略

    # tuple(元组)
    tuple1 = (1, 2, "张三", 3.14, [1, 3])
    print(type(tuple1))  # <class 'tuple'>
    tuple2 = 1, 2, "张三", 3.14, [1, 3]
    print(type(tuple2))  # <class 'tuple'>
    

5.Set(集合)

  • 集合是一种无序、可变的数据类型,用于存储唯一的元素

  • 集合中的元素不会重复,并且可以进行交集、并集、差集等常见的集合操作

  • 特性:默认去重(集合里面不存在重复的数据)

  • 集合无法存在列表和字典

    # set(集合)
    set1 = {1, 3.14, "张三", True, (1, 4)}
    print(type(set1))  # <class 'set'>
    

注意:创建一个空集合必须用 set() 而不是 { },因为 { } 是用来创建一个空字典。

6.Dictionary(字典)

  • 列表是有序的对象集合,字典是无序的对象集合。两者之间的区别在于:字典当中的元素是通过键来存取的,而不是通过偏移存取

  • 字典是一种映射类型,字典用 { } 标识,它是一个无序的 键(key) : 值(value) 的集合

  • 键(key)必须使用不可变类型

  • 在同一个字典中,键(key)必须是唯一的

    # dict(字典)
    dict1 = {"name": "张三", "age": 18, "sex": "男"}
    print(type(dict1))  # <class 'dict'>
    

三、输入和输出

1.读取键盘输入

  • 接收用户输入的数据可以调用内建函数:input()实现数据获取

  • 一般输入的数据会保存到变量中,默认情况获取的所有用户输入的内容都是字符串

  • 当程序执行的时候遇到input内建函数,程序会挂起(如果不输入回车)那么代码不会继续往下执行

    username = input("请输入用户名")
    password = input("请输入密码")
    print(f"您输入的用户名是:{username},密码是:{password}")
    

2.格式化输出

  • 格式化定义:按照指定的方式,拼接新的字符串内容(简单理解:当需要输出一个字符串的同时,也进行输出变量值)

方式一(不常用,了解即可):

  • 使用占位符号 % 实现格式化输出

  • 需要根据变量值的不同数据类型进行不同参数的占位

    • 格式化输出字符串类型:%s占位
    • 格式化输出整数类型:%d占位
    • 格式化输出浮点类型:%f占位
    name = "张三"
    age = 18
    height = 1.98
    print("我的名字是:%s" % name)  # 格式化输出字符串
    print("我的年龄是:%d" % age)  # 格式化输出整数
    # 浮点数格式化输出时默认保留6位小数
    # 如果需要保留指定的小数位,需要进行修改,那么在f前面加上.2f(保留2为小数)
    print("我的身高是:%f米" % height)  # 格式化输出浮点数
    print("我的身高是:%.2f米" % height)
    
  • 多个格式化输出的语法格式

    name = "张三"
    age = 18
    height = 1.98
    # 多个格式化输出的语法格式
    print("我的名字是:%s,我的年龄是:%d,我的身高是:%.2f米" % (name, age, height))
    

方式二(不常用,了解即可):

  • 任何的数据类型都可以放到{}进行格式化输出
name = "张三"
age = 18
height = 1.98
# 简写模式
print(f"我的名字是:{name},我的年龄是:{age},我的身高是:{height}米")
print(F"我的名字是:{name},我的年龄是:{age},我的身高是:{height}米")
# 完整模式
print("我的名字是:{},我的年龄是:{},我的身高是:{}米".format(name, age, height))

四、数据类型转换

数据类型转换的内建函数

函数作用
int()转换为整数数据类型
float()转换为浮点数数据类型
str()转换为字符串数据类型
eval()用来计算在字符串中的有效Python表达式,并返回一个对象(将字符串原生的数据类型转化为原本的类型)
  • int():转换为整数数据类型

    str1 = "666"
    print(type(str1))  # <class 'str'>
    # int()函数——将字符串的原生整数类型进行转化
    print(type(int(str1)))  # <class 'int'>
    
  • float():转换为浮点数数据类型

    str2 = "666"
    # float()函数——将字符串的原生浮点类型进行转化
    print(type(str2))  # <class 'str'>
    print(type(float(str2)))  # <class 'float'>
    
  • str():转换为字符串数据类型(万物皆可字符串:任何数据类型都可以加上引号变成字符串)

    number = 666
    print(type(number))  # <class 'int'>
    # str()函数——将原生的数据类型转化为字符串
    print(type(str(number)))  # <class 'str'>
    
  • eval():将字符串原生的数据类型转化为原本的类型

    str3 = "[1,2,3]"
    print(type(str3))  # <class 'str'>
    print(type(eval(str3)))  # <class 'list'>
    str4 = "(1,2,3)"
    print(type(str4))  # <class 'str'>
    print(type(eval(str4)))  # <class 'tuple'>
    str5 = "{1,2,3}"
    print(type(str5))  # <class 'str'>
    print(type(eval(str5)))  # <class 'set'>
    str6 = '{"name": "张三", "age": "18"}'
    print(type(str6))  # <class 'str'>
    print(type(eval(str6)))  # <class 'dict'>
    str7 = "666"
    print(type(str7))  # <class 'str'>
    print(type(eval(str7)))  # <class 'int'>
    

五、运算符

1.算术运算符

以下假设变量 a=5,变量 b=2

运算符描述实例
+a + b 输出结果 7
-a - b 输出结果 3
*a * b 输出结果 10
/a / b 输出结果 2.5
%取模(返回除法的余数)a % b 输出结果 1
**a ** b 输出结果 25
//取整除a // b 输出结果 2

2.比较(关系)运算符

以下假设变量 a=5,变量 b=2

运算符描述实例
==等于(a == b) 返回 False
!=不等于(a != b) 返回 True
>大于(a > b) 返回 True
<小于(a < b) 返回 False
>=大于等于(a >= b) 返回 True
<=小于等于(a <= b) 返回 False

注意:比较运算符返回的结果类型是布尔值。要么是True,要么是False

3.赋值运算符

运算符描述实例
=简单的赋值运算符
+=加法赋值运算符
-=减法赋值运算符
*=乘法赋值运算符
/=除法赋值运算符
%=取模赋值运算符
**=幂赋值运算符
//=取整除赋值运算符
:=海象运算符

4.逻辑运算符

  • and:两个条件必须同时满足最终结果为真
  • or:两个条件只要一个为真,最终结果为真
  • not:取反,假变真,真变假
运算符描述实例
and布尔"与"
or布尔"或"
not布尔"非"

5.位运算符

运算符描述实例
&与运算符
|或运算符
^异或运算符
~取反运算符
<<左移动运算符
>>右移动运算符

6.成员运算符

运算符描述实例
in如果在指定的序列中找到值返回 True,否则返回 False。
not in如果在指定的序列中没有找到值返回 True,否则返回 False。

7.身份运算符

运算符描述实例
isis 是判断两个标识符是不是引用自一个对象
is notis not 是判断两个标识符是不是引用自不同对象

8.运算符优先级

以下表格列出了从最高到最低优先级的所有运算符, 相同单元格内的运算符具有相同优先级。 运算符均指二元运算,除非特别指出。 相同单元格内的运算符从左至右分组(除了幂运算是从右至左分组):

运算符描述
(expressions…),
[expressions…], {key: value…}, {expressions…}
圆括号的表达式
x[index], x[index:index], x(arguments…), x.attribute读取,切片,调用,属性引用
await xawait 表达式
**乘方(指数)
+x, -x, ~x正,负,按位非 NOT
*, @, /, //, %乘,矩阵乘,除,整除,取余
+, -加和减
<<, >>移位
&按位与 AND
^按位异或 XOR
|按位或 OR
in,not in, is,is not, <, <=, >, >=, !=, ==比较运算,包括成员检测和标识号检测
not x逻辑非 NOT
and逻辑与 AND
or逻辑或 OR
if – else条件表达式
lambdalambda 表达式
:=赋值表达式

六、Python常见数据类型具体操作方法

1.字符串常用的操作方法

  • 字符串的索引及切片

    • 索引

      • 字符串是一种有序容器类型的数据,可以通过下标(索引)取值
      • 字符串可以通过索引值的正负两极取值
        • 从左到右默认从0开始

        • 从右到左默认从-1开始

          str1 = "今天又是充满希望的的一天"
          # 可以通过字符串的索引值取字符的实际值
          print(str1[1])  # 天
          print(str1[-2])  # 一
          
    • 切片

      • 切片是指对被操作的字符串对象的内容取一部分值,列表,元组都是支持切片操作

      • 切片的语法格式:[起始:结束:步长]

        str1 = "今天又是充满希望的的一天"
        # 只写开始,不写结束:默认到最后(默认包含开始索引值的内容)
        print(str1[6:])  # 希望的的一天
        # 有开始也有结束:包含开始的索引值,不包含结束的索引值
        # 切片的操作是一个左闭右开的区间
        print(str1[6:9])  # 希望的
        # 只写结束,不写开始:默认从0(索引)开始
        print(str1[:9])  # 今天又是充满希望的
        # 开始结束都不写
        print(str1[:])  # 今天又是充满希望的的一天
        # 对字符串切片操作是可以通过负数索引进行切片操作
        print(str1[6:-4])  # 希望
        # 当开始和结束的索引值没有交集的时候会取不到实际值
        print(str1[-1:6])
        # 步长,不写开始不写结束,步长为2
        print(str1[::2])  # 今又充希的一
        
  • 查找字符串中具体某个元素

    • 方法一:使用find()
      str1 = "今天又是充满希望的的一天"
      # 如果该字符串有该元素那么返回元素的索引值
      print(str1.find("希"))  # 6
      # 如果该字符串没有该元素那么返回的索引值是-1(表示没有该元素)
      print(str1.find("快"))  # -1
      
    • 方法二:使用index()
      str1 = "今天又是充满希望的的一天"
      # 如果该字符串有该元素那么返回元素的索引值
      print(str1.index("希"))  # 6
      # 如果该字符串没有该元素那么程序会报错
      print(str1.index("快"))  # 报错
      
  • count()统计元素在整个字符串当中出现的次数

    str1 = "今天又是充满希望的的一天"
    # 会返回该元素在整个字符串当中出现的次数
    print(str1.count("天"))  # 2
    
  • replace()替换字符串中的元素值

    str1 = "今天又是充满希望的的一天"
    # 替换字符串中的元素值
    print(str1.replace("今", "明"))
    
  • 使用split()对字符串进行切片

    str1 = "今天又是充满希望的的一天"
    # split对字符串进行切片的方法,返回的数据类型是列表,可以设置参数切几次,切好的数据是字符串类型
    print(str1.split("天", 1))  # ['今', '又是充满希望的的一', '']
    
  • capitalize()首字母大写,其余全部小写

    # capitalize()将整个字符串第一个元素(不管是大小写全部做大写处理)之后的内容里面的所有大写字母转化成小写字母
    str2 = "abcdABCD"
    print(str2.capitalize())  # Abcdabcd
    
  • title()根据字符串的空格将每个空格之后的首字母大写

    str3 = "abcd zxcv qwer"
    # 根据字符串的空格将每个空格之后的首字母大写(前提是空着之后是字母)
    print(str3.title())  # Abcd Zxcv Qwer
    
  • startswith()检测字符串是否以指定元素开头

    str4 = "good good stady day day up"
    # 检测字符串是否以指定元素开头
    print(str4.startswith("g"))  # True
    print(str4.startswith("b"))  # False
    print(str4.startswith("good"))  # True
    
  • lower()将整个字符串当中的所有大写字母转化为小写

    str5 = "I Love You"
    # 将整个字符串当中的所有大写字母转化为小写
    print(str5.lower())  # i love you
    
  • 去除自字符串前面或后面的空格元素

    • 去除前面空格元素:lstrip()
    • 去除后面空格元素:rstrip()
    • 去除前后空格元素:strip()
    # 去除自字符串前面或后面的空格元素
    str6 = " I Love You "
    # 去除后面空格元素
    print(str6.rstrip())  # " I Love You"
    # 去除前面空格元素
    print(str6.lstrip())  # "I Love You "
    # 去除前后空格元素
    print(str6.strip())  # I Love You
    
  • isdigit()判断字符串所有的元素是否由纯数字组成

    str7 = "12345qwer"
    # 判断字符串所有的元素是否由纯数字组成
    print(str7.isdigit())  # False
    
  • 使用固定的字符隔开字符串当中的所有元素

    str8 = "abcd1234"
    # 字符串的拼接操作:使用固定的字符隔开字符串当中的所有元素
    print("*".join(str8))  # a*b*c*d*1*2*3*4
    print("-".join(str8))  # a-b-c-d-1-2-3-4
    print("0".join(str8))  # a0b0c0d01020304
    

2.列表常用的操作方法

  • 列表中增加数据

    • 第一种方式:append()添加数据(默认是追加到列表末尾)

      name_list = ["宝总", "爷叔", "小江西", "蔡司令"]
      # 第一种方式:append()添加数据(后默认是追加到列表末尾)
      name_list.append("汪小姐")
      print(name_list)  # ['宝总', '爷叔', '小江西', '蔡司令', '汪小姐']
      
    • 第二种方式:append()插入数据

      name_list = ["宝总", "爷叔", "小江西", "蔡司令"]
      # 第二种方式:append()插入数据
      # 插入到元素下标为1的位置
      name_list.insert(1, "李李")
      print(name_list)  # ['宝总', '李李', '爷叔', '小江西', '蔡司令']
      
    • 第三种方式:extend()将容器类型数据拆分开来再添加

      name_list = ["宝总", "爷叔", "小江西", "蔡司令"]
      # 第三种方式:extend()将容器类型数据拆分开来再添加
      name_list.extend(["李李", "汪小姐"])
      print(name_list)  # ['宝总', '爷叔', '小江西', '蔡司令', '李李', '汪小姐']
      
  • 列表中查询数据

    • 列表可以通过索引取值(元素),也支持切片操作

      list1 = ["a", "b", "c", "d", "e"]
      print(list1[3])  # d
      print(list1[1:4])  # ['b', 'c', 'd']
      print(list1[::2])  # ['a', 'c', 'e']
      
    • 如果列表的切片步长为-1那么可以将列表反转

      list1 = ["a", "b", "c", "d", "e"]
      print(list1[::-1])  # ['e', 'd', 'c', 'b', 'a']
      
  • 列表中修改数据

    • 通过索引修改数据:先获取具体要修改的索引值内容然后再赋值

      list1 = ["a", "b", "c", "d", "e"]
      # 通过索引修改数据:先获取具体要修改的索引值内容然后再赋值
      list1[1] = "张三"
      print(list1)  # ['a', '张三', 'c', 'd', 'e']
      
  • 列表中删除数据(当数据被删除的时候,因为列表是有序的序列,那么现存的数据索引会发生变化)

    • 使用pop()方法删除

      name_list1 = ["宝总", "爷叔", "小江西", "蔡司令", "李李", "汪小姐"]
      # 使用pop()方法删除
      name_list1.pop(2)
      print(name_list1)  # ['宝总', '爷叔', '蔡司令', '李李', '汪小姐']
      
    • 使用remove()方法删除

      name_list1 = ["宝总", "爷叔", "小江西", "蔡司令", "李李", "汪小姐"]
      # 使用remove()方法删除
      name_list1.remove("蔡司令")
      print(name_list1)  # ['宝总', '爷叔', '小江西', '李李', '汪小姐']
      
    • 使用clear()清除列表中所有的数据

      name_list1 = ["宝总", "爷叔", "小江西", "蔡司令", "李李", "汪小姐"]
      # 使用clear()清除列表中所有的数据
      name_list1.clear()
      print(name_list1)  # []
      
    • 使用特殊关键字del删除具体某个数据(通过索引获取)

      name_list1 = ["宝总", "爷叔", "小江西", "蔡司令", "李李", "汪小姐"]
      # 使用特殊关键字del删除具体某个数据(通过索引获取)
      del name_list1[2]
      print(name_list1)  # ['宝总', '爷叔', '蔡司令', '李李', '汪小姐']
      
  • reverse()列表反转

    name_list1 = ["宝总", "爷叔", "小江西", "蔡司令", "李李", "汪小姐"]
    # 列表反转
    name_list1.reverse()
    print(name_list1)  # ['汪小姐', '李李', '蔡司令', '小江西', '爷叔', '宝总']
    
  • count()统计元素在整个列表当中出现的次数

    name_list1 = ["宝总", "爷叔", "小江西", "蔡司令", "李李", "汪小姐"]
    print(name_list1.count("爷叔")) # 1
    
  • index()查询列表当中某个元素的索引值

    name_list1 = ["宝总", "爷叔", "小江西", "蔡司令", "李李", "汪小姐"]
    print(name_list1.index("宝总")) # 0
    
  • sort()将列表中的数据进行排序

    • 从小到大排序

      list2 = [3, 5, 1, 7, 16, 12, 20, 2]
      # sort()将列表中的数据进行排序(从小到大排序)
      list2.sort()
      print(list2)  # [1, 2, 3, 5, 7, 12, 16, 20]
      
    • 从大到小排序

      list2 = [3, 5, 1, 7, 16, 12, 20, 2]
      # 从大到小进行排序
      list2.sort(reverse=True)
      print(list2)  # [20, 16, 12, 7, 5, 3, 2, 1]
      

3.元组常用的操作方法


元组和列表是一样,都是有序的容器类型的数据,但是区别是元组的数据不能被修改,当数据一旦被定义那么就是固定值,元组只支持查询数据功能。

t1 = (1, 2, 3, 4, 5, 6)
# 可以通过索引取值
print(t1[3])
# 可以支持切片操作
print(t1[0:2])
# index,count
print(t1.count(3)) # 1
print(t1.index(2)) # 1

4.字典常用的操作方法

  • 字典的特性:

    • 可以进行切片和索引取值
    • 元素的位置很重
  • 字典的快速创建键值对

    dict2 = dict(a=1, b=2, c=3)
    print(dict2)  # {'a': 1, 'b': 2, 'c': 3}
    
  • 字典中查询数据

    • 通过字典的键取值

      dict1 = {"name": "张三", "age": 18, "sex": "男"}
      # 字典取值:通过字典的键取值
      print(dict1["name"])  # 张三
      
    • 查看字典中所有的键

      dict1 = {"name": "张三", "age": 18, "sex": "男"}
      # 查看字典中所有的键
      print(dict1.keys())  # dict_keys(['name', 'age', 'sex'])
      
    • 查看指点中所有的值

      dict1 = {"name": "张三", "age": 18, "sex": "男"}
      # 查看指点中所有的值
      print(dict1.values())  # dict_values(['张三', 18, '男'])
      
    • 获取字典的所有键值对

      dict1 = {"name": "张三", "age": 18, "sex": "男"}
      # 获取字典的所有键值对
      print(dict1.items())  # dict_items([('name', '张三'), ('age', 18), ('sex', '男')])
      
  • 字典中增加数据

    • 字典中的键一定是唯一的,值随意,当字典中有当前的键值对的时候,那么会通过键覆盖值

    • update()给字典添加数据:支持单个键值对添加和多个键值对添加

      dict3 = {'a': 1, 'b': 2, 'c': 3}
      dict3.update({"d": 4, "e": 5})
      print(dict3)  # {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}
      
    • setdefault()添加字典中没有键的键值对数据

      dict3 = {'a': 1, 'b': 2, 'c': 3}
      dict3.setdefault("d", 4)
      print(dict3)
      
  • 字典中修改数据

    • 通过字典的键去修改值

      dict4 = {'a': 1, 'b': 2, 'c': 3}
      dict4["a"] = 11
      print(dict4)  # {'a': 11, 'b': 2, 'c': 3}
      
  • 字典中删除数据

    • 通过del关键字删除值(键获取,最终是将整个键值对全部删除)
      dict5 = {'a': 1, 'b': 2, 'c': 3}
      del dict5["a"]
      print(dict5)  # {'b': 2, 'c': 3}
      
    • 通过pop()方法删除,通过键删除键值对
      dict5 = {'a': 1, 'b': 2, 'c': 3}
      dict5.pop("a")
      print(dict5)  # {'b': 2, 'c': 3}
      
    • clear()清空字典
      dict5 = {'a': 1, 'b': 2, 'c': 3}
      dict5.clear()
      print(dict5)  # {}
      

5.集合常用的操作方法


集合的特性就是去重,集合里面不存在重复的数据,集合的数据(元素)都是唯一的

集合默认是无序的序列,不能进行索引取值和切片,因为集合中的元素是没有前后顺序的

  • 集合中新增数据

    set1 = {1, 2, 3, 4, 5}
    # 集合可以添加数据,前提是集合中没有这个数据才能添加成功
    set1.add(6)
    print(set1)  # {1, 2, 3, 4, 5, 6}
    
  • 集合中删除数据

    set2 = {"a", 1, "张三", 2}
    set2.remove("a")
    print(set2)  # {1, 2, '张三'}
    

6.列表、元组、集合的相互转化

  • 列表转元组

    list1 = [1, 2, 3, 3, 4, 5, 6, 7]
    # 列表转元组
    tuple1 = tuple(list1)
    print(tuple1)  # (1, 2, 3, 3, 4, 5, 6, 7)
    print(type(tuple1))  # <class 'tuple'>
    
  • 元组转集合

    tuple2 = (1, 2, 3, 3, 4, 5, 6, 7)
    # 元组转集合
    set1 = set(tuple2)
    print(set1)  # {1, 2, 3, 4, 5, 6, 7}
    print(type(set1))  # <class 'set'>
    
  • 列表转集合

    list1 = [1, 2, 3, 3, 4, 5, 6, 7]
    # 列表转集合
    set2 = set(list1)
    print(set2)  # {1, 2, 3, 4, 5, 6, 7}
    print(type(set2))  # <class 'set'>
    
  • 如果列表和元组中的数据需要去重,那么可以直接转集合,再转回去

    # 如果列表和元组中的数据需要去重,那么可以直接转集合,再转回去
    # 集合变元组或者列表:去重案例
    list1 = [1, 2, 3, 3, 4, 5, 6, 7]
    print(list(set(list1)))  # [1, 2, 3, 4, 5, 6, 7]
    print(tuple(set(list1)))  # (1, 2, 3, 4, 5, 6, 7)
    

七、Python中的可变数据类型与不可变数据类型


可变数据类型:当数据类型变量的值发生变化,内存地址值不变,那么该数据类型就是可变数据类型(内存地址值是唯一的)

  • 可变数据类型:对元素可以进行任意的操作(增删改查)
    • 列表
    • 集合
    • 字典

不可变数据类型:当数据类型变量的值发生变化,内存地址值改变,那么该数据类型就是不可变数据类型

  • `不可变数据类型:对元素不能进行任意的操作(增删改查)
    • 数字类型
      • 整数类型
      • 浮点数类型
      • 布尔类型
    • 字符串
    • 元组

注意:字典的键一定是不可变的数据类型。字典,列表,集合不能当做字典的键。字典的值没有数据类型的要求

注意:集合中的元素只能放不可变的数据类型

八、浅拷贝与深拷贝

1.浅拷贝

  • 浅拷贝:针对不可变的数据类型进行拷贝

  • 浅拷贝:复制一份数据,重新分配一块内存空间(引用原来数据值的内存地址),新的数据里面的值指向还是原来值的内存地址

  • 引用:不同的变量里面保存的值是一样的时候,会在内存里面引用同一个内存地址值

  • 浅拷贝可以通过赋值 = 来实现

  • 浅拷贝:copy可以复制一份数据,但是引用地址还是原来数据的内存地址

  • 浅拷贝只针对不可变的数据类型有效:数字类型,字符串,元组

  • 针对不可变的数据类型,如果原数据被删除,只要内存地址在,那么被拷贝数据照常使用

    # 从指定的模块中导入指定的对象或函数,并将其命名为copy,之后就可以直接使用copy来调用该对象(第一个copy代表模块名,第二个copy代表模块中的对象或者函数名)
    from copy import copy
    str1 = "今天又是充满希望的一天!"
    str2 = copy(str1)
    print(id(str1))
    print(id(str2))
    

案例:使用浅拷贝对可变数据类型进行拷贝

from copy import copy
list1 = ["张三"]
list2 = []
copy_list1 = copy(list2)
new_list1 = list2.extend(["李四", list1])
copy_list2 = copy(list2)
new_list2 = list2.extend(["李四", list1])
list1.append("王五")
print(list2)  # ['李四', ['张三', '王五'], '李四', ['张三', '王五']]
print(copy_list1)  # []
print(copy_list2)  # ['李四', ['张三', '王五']]

注意:可变的数据类型不建议使用浅拷贝,因为当拷贝完之后,对原来数据进行修改,所有被拷贝好的数据也会发生变化

2.深拷贝

  • 深拷贝:针对可变的数据类型进行拷贝

  • 深拷贝可以对可变的数据类型进行拷贝,拷贝好的数据发生变化都是相互独立的不会受到影响

    from copy import deepcopy
    list1 = ["张三"]
    list2 = []
    copy_list1 = deepcopy(list2)
    new_list1 = list2.extend(["李四", list1])
    copy_list2 = deepcopy(list2)
    new_list2 = list2.extend(["李四", list1])
    list1.append("王五")
    print(list2)  # ['李四', ['张三', '王五'], '李四', ['张三', '王五']]
    print(copy_list1)  # []
    print(copy_list2)  # ['李四', ['张三']]
    

注意:可变和不可变的数据类型都可以进行深拷贝,不可变的数据类型不建议使用深拷贝,比较占用内存

3.总结

1

  • 使用浅拷贝拷贝可变的数据类型:源数据变化,被拷贝的数据也会变化

  • 使用深拷贝拷贝可变的数据类型:源数据变化,被拷贝的数据不会变化

  • 不可变的数据类型建议使用浅拷贝

    • 不可变的数据类型使用浅拷贝和深拷贝的效果一样(但深拷贝比较占用内存)
  • 可变的数据类型一定要使用深拷贝

  • 不可变的数据类型使用方法操作完之后都是全新的数据,跟原来数据没有任何关系

    • 因为字符串是不可变的数据类型,当使用字符串的所有方法时,生成都是全新地址全新值的数据,所以不会对源数据造成任何影响,方法执行会生成一个新的字符串,会开辟新的内存地址值
  • 可变的数据类型使用方法操作完之后都是对原来的数据进行修改,跟原来的数据有密切的关系

  • 数据的内容发生变化,都是在同一块内存地址值,内存地址值不会发生任何变化

九、流程控制

  • 所有程序执行都有三大体系
    • 顺序
    • 分支
    • 循环

1.if分支语句

  • if分支语句

    age = int(input("请输入您的年龄"))
    if age >= 18:
        print("您已成年,可以上网")
    else:
        print("您未成年,禁止上网")
    
  • 分支语句-多条件判断

    score = int(input("请输入成绩1-100"))
    if score >= 90:
        print("优秀")
    elif score >= 80 and score < 90:
        print("良好")
    elif score >= 60 and score < 80:
        print("及格")
    else:
        print("不及格")
    
  • if语句后面跟随的判断条件是通过布尔值判断的

    • Frue
    • False
  • Python中所有的数据类型,都可以转化为布尔值

    • Frue
      • 非0的数字:小数,整数,负数
      • 非空的字符串
      • 非空的容器类型数据:列表,集合,元组,字典等等
    • False
      • 数字为0
      • 为空的容器类型数据都为假
      if -1:
          print("真的")
      else:
          print("假的")
      

2.关键字match与case

  • 在Python3.10环境更新之后新增了2个匹配的关键字matchcase可以用来代替多种情况

    name = input("请输入您的姓氏")
    match name:
        case "王":
            print("排名第一")
        case "张":
            print("排名第二")
        case "李":
            print("排名第三")
        case "刘":
            print("排名第四")
    

3.三目运算符

  • 简写的if语句:比较两个数的大小

    import random
    a = int(input("请输入一个1-10的整数"))
    b = random.randint(1,10)
    print(f"您输入的数字是:{a},随机生成的数字是:{b},两个数最大的值是:{a if a > b else b}")
    

4.循环

4.1.for循环

  • for循环一般情况会结合range()内建函数一起使用构建循环体

    • 例子1
    # range(1,100)左闭右开天,1-99不包含100
    for i in range(1, 100):
        print(i)
    
    • 例子2
    # range(10)循环10次,从0开始9结束
    for i in range(10):
        print(i)
    
    • 例子3
    # range(10)循环10次,从0开始9结束
    for i in range(10):
        print(i)
    else:
        print("for循环结束会执行else后面的代码")
    
  • for循环可以遍历所有容器类型的数据

    • 例子1(字符串)
    str1 = "今天又是充满希望的一天!"
    index = 0
    for i in str1:
        print(f"当前元素的下标是:{index},元素具体值是:{i}")
        index += 1
    
    • 例子2(列表)
    list1 = [1, 2, 3, 4, "张三", "李四"]
    index = 0
    for i in list1:
        print(f"当前元素的下标是:{index},元素具体值是:{i}")
        index += 1
    
    • 例子3(字典)
    dict1 = {"name": "张三", "age": "18", "sex": "男"}
    # dict1.values()获取字典中的值
    for i in dict1.values():
        print(i)
    # dict1.items()获取字典中的键值对
    for i in dict1.items():
        print(i)
    

4.2.while循环

  • while循环和if语句类似,区别在于if语句条件成立只执行一次,while条件只要成立就一直执行,直到条件不成立

    i = 0
    while i < 100:
        print(i)
        i += 1
    
  • 死循环

    while True:
        print("死循环无限执行!!!")
    

4.3.循环中的关键字break与continue

  • break:退出当前整个循环

    for i in range(10):
        if i == 5:
            break
        print(i,end=" ")
    else:
    	# 循环正常结束才会执行下面的代码
        # 当循环中没有出现break终止循环那么else里面的代码就会执行
        print("准备就绪")
    
    i = 0
    while i <= 10:
        i += 1
        if i == 8:
            break
        print(i, end=" ")
    else:
        # 循环正常结束才会执行下面的代码
        # 当循环中没有出现break终止循环那么else里面的代码就会执行
        print("准备就绪")
    
  • continue:跳出当次循环,继续下一次循环

    for i in range(10):
        if i == 5:
            continue
        print(i,end=" ")
    else:
    	# 循环正常结束才会执行下面的代码
        # 当循环中没有出现break终止循环那么else里面的代码就会执行
        print("循环结束")
    
    i = 0
    while i <= 10:
        i += 1
        if i == 8:
            continue
            # break
        print(i, end=" ")
    else:
        # 循环正常结束才会执行下面的代码
        # 当循环中没有出现break终止循环那么else里面的代码就会执行
        print("循环结束")
    

十、函数

  • 什么是函数:函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段

  • 函数的核心作用:提高应用的模块性,和代码的重复利用率

  • 函数一般分为两种类型:

    • 内建函数:Python自带封装好的函数直接可以使用
    • 自定义函数:开发人员通过def关键字自定义函数功能
  • 函数定义好了之后并不会执行,需要手动的调用才会执行。不管是内建函数还是自定义函数使用的时候都是通过函数名()进行使用

  • 函数的三大要素

    • 形参:形式参数(定义函数时,函数名后面括号内定义的参数叫做形参)
    • 实参:实际参数(调用函数的时候,函数名后面括号内传递的值叫做实参)
    • 返回值(定义函数时,函数体中通过return关键字返回的内容叫做返回值)

1.函数的定义与调用

  • 函数语法:

    def 函数名(参数列表):
        函数体
    
  • 定义函数使用def关键字,调用函数:函数名(实参)

    # 定义函数
    def sum(x, y):
        result = x + y
        # 返回值return:return会结束当前函数的执行,当功能结束之后需要返回到函数外部的内容
        return result
    
    
    # 调用函数
    number = sum(10, 20)
    print(number)  # 30
    

2.指定形参和返回值的类型

  • 位置参数:有几个形参就传递几个实参, 不能多也不能少

  • 如果对函数的形参(返回值)进行指定类型,在调用函数的时候会有说明

    # 指定形参的类型,返回值的类型
    def celc(number1: int, number2: int, arithmetical: str) -> float:
        if arithmetical == "+":
            return number1 + number2
        elif arithmetical == "-":
            return number1 - number2
        elif arithmetical == "*":
            return number1 * number2
        elif arithmetical == "/":
            return number1 / number2
        else:
            print("对不起,您输入的是不支持的运算符")
    
    
    # 位置参数:有几个形参就传递几个实参, 不能多也不能少
    print(celc(10, 20, "+"))
    

注意:如果指定了类型,那么不一定要求规定类型也可以正常使用

3.关键字参数

  • 关键字参数:通过关键字,来决定参数,指定传参

  • 知道形参的前提下,可以指定形参传递实参值,实参通过关键字(形参)指定传过去

    def function(a, b, c):
        print(a)
        print(b)
        print(c)
    
    
    function(c=2, a=3, b=5)
    
  • 关键字传参一般结合位置参数一起使用

    def function(a, b, c):
        print(a)
        print(b)
        print(c)
    
    
    function(777, c=4, b=5)
    

注意:如果结合位置参数一起使用那么关键字参数要在位置参数后面

4.默认参数

  • 如果使用默认形参,那么必须放到所有参数的最后面

  • 如果形参有默认值,调用函数的时候可以不传递实参。如果传递了实参那么直接覆盖默认值。如果不传递实参,那么就使用默认值。

    def function(a, c, b=20):
        print(a)
        print(b)
        print(c)
    
    
    function(a=10, c=30)
    

5.不定长参数

5.1.不定长位置参数*args

  • 不定长位置参数用*args表示,如果函数使用不定长形参,那么可以接收任意的实参,而且是以元组的数据类型进行存储(加了一个星号 * 的参数会以元组(tuple)的形式导入)

  • 不定长参数可以让函数接受不确定长度的实参,可以是0到任意个参数

    def function(*args):
        print(args)
    
    
    function("张三",20,3.14)
    
  • 一般情况不定长的形参会结合位置参数一起使用(当位置形参结合不定长参数一起使用的时候,需要把位置参数放到不定长形参的前面)

    # 不定长参数
    def function(a, b, *args):
        print(a)
        print(b)
        print(args)
    
    
    function(10, 20, "张三", 30)
    

5.2不定长关键字参数**kwargs

  • 不定长关键字参数**kwargs(加了两个星号**的参数会以字典的形式导入)
def function(**kwargs):
    print(kwargs)


function(name="张三", age=18, sex="男")  # {'name': '张三', 'age': 18, 'sex': '男'}

6.函数的局部变量与全局变量

  • 在函数中,当全局变量和局部变量重名时,默认优先使用局部变量

    # 全局变量
    # 作用域:可以在函数内部使用,整个py文件也可以使用
    number = 888
    
    
    def function():
        # number变量在函数内部叫做局部变量
        # 作用域:仅仅是在function函数里面进行使用,函数外部不能进行使用
        number = 666
        print(f"函数内部number的值是:{number}")
    
    
    print(f"函数调用之前number的值是:{number}")  # 888
    function()  # 666
    print(f"函数调用之后number的值是:{number}")  # 888
    
  • 在函数中,当全局变量和局部变量重名时,默认优先使用局部变量。如果一定要使用全局变量,那么可以使用关键字global进行声明,声明之后没有局部变量只会有全局变量

    # 全局变量
    # 作用域:可以在函数内部使用,整个py文件也可以使用
    number = 888
    
    
    def function():
        # number变量在函数内部叫做局部变量
        # 作用域:仅仅是在function函数里面进行使用,函数外部不能进行使用
        global number  # number = 888
        number = 666  # number = 666
        print(f"函数内部number的值是:{number}")
    
    
    print(f"函数调用之前number的值是:{number}")  # 888
    function()  # 666
    print(f"函数调用之后number的值是:{number}")  # 666
    

7.匿名函数

  • 使用 lambda 来创建匿名函数

  • 所谓匿名,意即不再使用 def 语句这样标准的形式定义一个函数

    • lambda 只是一个表达式,函数体比 def 简单很多
    • lambda 的主体是一个表达式,而不是一个代码块。仅仅能在 lambda 表达式中封装有限的逻辑进去
    • lambda 函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数
  • 匿名函数的特点:

    • 匿名函数可以有名字,可以没有
    • 匿名函数调用跟普通函数没有区别
    • 匿名函数没有使用 return 关键字也有返回值
    • 匿名函数没有名字也可以调用,定义完函数之后加 () 进行调用
  • 匿名函数的定义和使用:

    # 匿名函数使用lambda关键字定义
    # a,b:代表形参,a+b:代表函数内容(返回值)
    # function代表匿名函数的名字(自定义)
    function = lambda a, b: a + b
    # 调用匿名函数
    result = function(10, 20)
    print(result)  # 30
    
  • 匿名函数简写:没有名字直接使用

    print((lambda a, b: a + b)(20, 30))  # 50
    

8.函数闭包

  • 闭包就是能够读取其他函数内部变量的函数,在本质上,闭包是将函数内部和函数外部连接起来的桥梁

  • 闭包的定义:在函数的嵌套前提下,内部函数使用了外部函数的变量,并且外部函数返回了内部函数的引用(内部函数的名字),核心点是内部函数使用外部函数的变量,我们把这个构造叫做闭包。

  • 闭包的意义:函数被调用完,函数内的局部变量会被销毁,为了方便保存进行闭包操作

  • 闭包的构成条件:

    • 1.在函数嵌套的前提下形成
    • 2.内部函数使用了外部函数的变量
    • 3.外部函数返回了内部函数的引用(内部函数的名字)
  • 闭包的作用:

    • 闭包可以保存外部函数的变量,不会随着外部函数调用完就被销毁
    • 由于闭包引用了外部函数的变量,外部函数的变量并没有得到释放,会保存到内存进行消耗
    • 函数的引用(函数的名字)可以进行传递,如果复制给一个变量,那么该变量加上括号()那么就可以进行调用,指向的函数引用
  • 闭包语法结构的定义和使用

  • 案例一:

    def function(*args, **kwargs):
        def sum(a, b):
            return a + b
    
        return sum
    
    
    # 如何执行add函数?
    # 方法一
    result = function()(10, 30)
    print(result)  # 40
    # 方法二
    sum = function()
    result1 = sum(20, 30)
    print(result1)  # 50
    
  • 案例二:

    def function_out(number1):
        def function_inner(number2):
            result = number1 + number2
            print(f"外部函数的值是:{number1},内部函数的值是:{number2},两个值相加的结果是:{number1 + number2}")
    
        return function_inner
    
    
    f = function_out(10)
    f(30)  # 外部函数的值是:10,内部函数的值是:30,两个值相加的结果是:40
    
    # 简写
    function_out(10)(40)  # 外部函数的值是:10,内部函数的值是:40,两个值相加的结果是:50
    

十一、模块与包的使用

  • 模块是一个包含所有你定义的函数和变量的文件,其后缀名是.py。模块可以被别的程序引入,以使用该模块中的函数等功能(简单来说一个py文件就是一个模块,模块中包含变量、函数、类等,Python中的模块和包可以被其他模块进行导入使用)

    在这里插入图片描述

  • 包就是一个py文件集合的项目包(包里面可以有很多的模块(py文件))

    在这里插入图片描述

  • 如何导包

    • 方法一:

      # 导入random模块,将random模块里面所有的内容进行导入(变量,函数,类)
      import random
      # 调用模块里面的randint方法。通过模块名.方法名()进行调用
      print(random.randint(1, 10))
      
    • 方法二:

      # 指定功能导入(指定某一个变量,某一个函数,某一个类)
      # 具体导入某一个模块的方法或者函数以及变量或者类的时候可以用逗号隔开,导入多个
      from random import randint,randrange
      # 如果是通过模块具体导入某个方法那么直接通过方法名()进行调用
      print(randint(1, 10))
      
    • 方法三:

      • 在模块名比较复杂的情况下可以自定义模块名(符合标识符命名规则),如果使用了别名,原来的模块名会失效,只能用别名进行模块内容的调用
      # 导入random模块中的所有内容(* 代表被导入模块的所有内容)
      from random import *
      print(randint(1, 10))
      
    • 方法四:

      # 导入random模块,给random模块起别名为r
      import random as r
      # 使用模块别名.方法名()进行调用
      print(r.randint(1, 10))
      

注意:模块名和包名一定要符合标识符的命名规则

十二、Python异常处理

  • 异常定义:就是不符合语法规则,就会出现异常信息(bug,程序错误信息提示)

  • 异常信息如下:

    Traceback (most recent call last):
      File "D:\develop\PyCharm\workspace\pythonProjectSoftwareTest\30异常处理.py", line 1, in <module>
        print(a)
    NameError: name 'a' is not defined
    
  • 异常信心的溯源:File “D:\develop\PyCharm\workspace\pythonProjectSoftwareTest\30异常处理.py”, line 1, in <module>

  • 异常代码的具体详细信息: print(a)

  • 异常的描述信息:NameError: name ‘a’ is not defined

    在这里插入图片描述

异常捕获

  • 通过try关键字来捕获异常,通过except关键字进行异常出现后的处理方式

  • 如果try中没有出现异常,那么except里面的代码不会执行

  • 如果try中有异常,那么出现异常后会直接接执行except里面的代码,try中异常代码后面的代码不会继续执行

    try:
        print("捕获异常")
        print(a)
        print("捕获异常")
    except:
        print("捕获到了异常,开始执行某某程序")
    
  • elsefinally关键字一起使用

    • else:try当中没有出现异常,那么会执行else里面的代码
    • finally:不管try当中有没有出现异常,都会执行finally中的代码块
    try:
        print("捕获异常")
        print(a)
        print("捕获异常")
    except:
        print("try当中出现了异常,那么会执行except里面的代码块")
    else:
        print("try当中没有出现异常,那么会执行else里面的代码")
    finally:
        print("不管try当中有没有出现异常,都会执行finally中的代码块")
    

注意:try是可以进行嵌套使用的

十三、文件常用操作


文件就是在电脑当中进行持久化储存的内容,不同的文件有不同格式

1.常见的文件类型

  • 常见的文件类型:
    • 文本:.txt、.doc、.wap 等
    • 音频:.MP3、.wav、.wma、.midi 等
    • 图像:.jpeg、.jpg、.gif、png 等
    • 视频:.mp4、.avi、.mpg 等
    • 表格:.xlsx 等
    • 网页:.html 等
    • …… 等

2.文件的属性

  • 如果需要定位一个文件那么可以用不同的路径表示
    • 绝对路径:绝对路径是指目录下的绝对位置,直接到达目标位置,通常是从盘符开始的路径
      • 路径信息 + 文件名及格式
    • 相对路径:相对路径就是指由这个文件所在的路径引起的跟其它文件(或文件夹)的路径关系
      • 相对文件参照物不同,那么相对路径也会不同。相对某个具体文件的相对位置(不常用)
        • 路径信息可以进行跳转
        • ./代表当前目录
        • ../代表上级目录
        • ././/都是可以无限使用的

3.文件的读写模式

  • open():打开文件
  • read():读取文件(一次性读取文件全部内容)
  • write():写入内容到文件中
  • close():关闭文件

3.1.读

  • 读取文件内容

    • read():一次性读取文件全部内容
    • readline():读取一行
    • readlines():读取全部内容,每次一行一行读取,返回的是一个集合,以一行为列表的每个元素
    # 如果需要读(r)一个文件,当文件不存在的时候程序会报错
    # 打开文件open()
    # "C:/Users/xiongjian/Desktop/test.txt"代表文件所在路径和文件名
    # "r" 代表读,默认
    # encoding="utf-8"代表文件的编码格式
    file = open("C:/Users/xiongjian/Desktop/test.txt", "r", encoding="utf-8")
    # read()读取文件全部内容
    result = file.read()
    #打印文件内容
    print(result)
    # close()关闭文件
    file.close()
    

注意:如果需要读一个文件,当文件不存在的时候程序会报错

3.2.写

  • 写入内容到文件中

    # 打开文件open()
    # "C:/Users/xiongjian/Desktop/test.txt"代表文件所在路径和文件名
    # "w" 代表写
    # encoding="utf-8"代表文件的编码格式
    file = open("C:/Users/xiongjian/Desktop/test.txt", "w", encoding="utf-8")
    # write()写入内容
    file.write("这是我写入的内容")
    # close()关闭文件
    file.close()
    

注意:如果需要写文件,文件不存在的时候会自动生成一个文件并写入内容

3.3.读写模式总结

  • w:代表写入
    • 如果以写入的模式打开文件,文件不存在时会新建一个文件,然后进行写入
    • 如果以写入的模式打开文件,文件存在并且有内容的情况下,会覆盖原来内容,写入新内容
  • r:代表读取
    • 如果以读的模式打开文件,那么文件不存在时程序会报错
    • 不指定读写或其他参数打开文件,默认是以读的模式打开文件。因为形参有默认值是mode='r'
  • a:代表追加
    • 追加写入内容,不会将原来内容清除,而是追加到内容的末尾

注意:以上三种读写模式一般都是用于普通文本(txt格式的文件)。

  • 如果是其他文件:会以二进制的方式读取(所有文件的存储方式都是以二进制为主,所以以储存方式读取可以保证文件的完整性)
    • rb:以二进制的格式打开一个文件,用于读
    • wb:以二进制的格式打开一个文件,用于写
    • ab:以二进制的格式打开一个文件,用于追加写入
    • 二进制读写使用场景:图片、音频、视频、Excel等等

注意:如果是二进制的文件,那么不要指定编码格式,不然程序会报错

  • 任意的读写模式后面都可以加上+
  • 作用:可以让文件同时具备读写功能
    • r+
    • w+
    • a+
    • rb+
    • wb+
    • ab+

注意r+w+a+rb+wb+ab+ 可以对打开的文件对象模式进行读和写(但是不能同时进行)

4.文件的常用操作

  • 先导入os(文件操作)模块
    • remove():删除文件(如果删除的文件不存在,程序会报错)

      import os
      
      # remove()删除文件,注意:如果删除的文件不存在,程序会报错
      # r:当路径信息中有转义字符,可以消除转义
      os.remove(r"C:\Users\xiongjian\Desktop\test.txt")
      
    • renames():重命名

      import os
      
      # renames()重命名,语法:renames("原文件名","新文件名")
      # r:当路径信息中有转义字符,可以消除转义
      # 如果新文件名前面没有路径信息,那么默认保存在当前项目中,相当于原文件移动到当先项目路径并改名(注意:如果文件与项目文件不再同一个磁盘下代码会报错)
      os.renames(r"D:\test.txt", "tests.txt")
      
    • 复制

    • getcwd():获取当前文件的绝对路径信息

      import os
      
      # 获取当前文件的绝对路径信息
      print(os.getcwd())
      
    • mkdir():创建文件夹

      import os
      
      # mkdir()创建文件夹
      os.mkdir("test")
      
    • rmdir():删除文件夹(注意:如果删除一个不存在的文件夹会报错,删除非空文件夹也会报错)

      import os
      
      # rmdir()删除文件夹,注意:如果删除一个不存在的文件夹会报错,删除非空文件夹也会报错
      os.rmdir(r"C:\Users\xiongjian\Desktop\test")
      
    • listdir():获取文件夹内的文件及目录信息(返回的是一个列表)

      import os
      
      # listdir()获取文件夹内的文件及目录信息
      print(os.listdir(r"C:\Users\xiongjian\Desktop\test"))
      # 获取文件夹内的文件及目录个数
      print(len(os.listdir(r"C:\Users\xiongjian\Desktop\test")))
      

5.案例(删除一个非空的文件夹)

import os

# 创建一个函数
def delete_folder(path):
    # os.path.exists(path)判断返回路径是否存在。返回的是布尔值
    if os.path.exists(path):
        # 遍历文件夹下所有子目录和文件并删除
        # os.walk():扫描某个指定目录下所包含的子目录和文件,返回的是一个迭代器
        for root, dirs, files in os.walk(path, topdown=False):
            for file in files:
                # os.remove删除文件
                # os.path.join(root, file)把目录和文件名合成一个路径
                os.remove(os.path.join(root, file))
            for dir in dirs:
                # os.rmdir()删除文件夹
                # os.path.join(root, 文件夹)把目录和文件名合成一个路径
                os.rmdir(os.path.join(root, dir))
        os.rmdir(path)
    else:
        print("Folder not found 找不到文件夹")


# 调用函数:
delete_folder(r"C:\Users\xiongjian\Desktop\test")

十四、面向对象

  • 软件测试及开发比较主流的开发思想分为两种
    • 面向过程:需要实现一个功能的时候,看中的是开发的步骤和过程,每一个步骤都是亲力亲为用代码去编写然后实现功能
    • 面向对象:需要实现一个功能的时候,不看中开发的步骤和过程,核心是谁来帮我实现这个功能
      • 在面向对象的编程中,对象是数据和与之相关的操作的封装。这种范式使得代码更加模块化、可重用性更高,并且更易于理解和维护。
  • 面向对象的三大特征:
    • 封装
    • 继承
    • 多态

1.面向对象技术简介

  • 类(Class):用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例
  • 方法:类中定义的函数
  • 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用
  • 数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据
  • 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写
  • 局部变量:定义在方法中的变量,只作用于当前实例的类
  • 实例变量:在类的声明中,属性是用变量来表示的,这种变量就称为实例变量,实例变量就是一个用 self 修饰的变量
  • 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。
  • 实例化:创建一个类的实例,类的具体对象
  • 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法

2.封装

  • 将特征及行为封装成类
    • 特征:设置成类的实例属性
    • 行为:设置成类的实例方法
  • 类的基本定义和使用:
    • 如何定义类
    • 如何创建对象
    • 实例属性封装
    • 实例方法封装

1.1.类的实例属性定义和实例方法定义

  • 类的实例属性定义和实例方法定义

    • 类里面并且在init构造方法里面定义的变量,叫做实例属性
    • 类里面定义的函数,叫做实例方法,默认有个self参数(没人加任何装饰器)
    # 定义一个人类
    # 使用class关键字创建类:class关键字后面接类名(类名要符合标识符命名规则,并且一般推荐使用大驼峰命名法)
    # 在不发生继承的情况下,类后面的括号可写可不写
    class Person():
    
        # 类有一个名为 __init__() 的特殊方法(构造方法,有的称之为魔法方法),该方法在类实例化时会自动调用
        # 当对象一旦被创建,自动执行init构造方法里面的内容
        def __init__(self):
            # self代表对象本身
            # 特征:设置成类的实例属性
            # 对象的实例属性全部封装到init构造方法中
            self.name = "张三"
            self.age = 18
            self.sex = "男"
    
        # 行为:设置成类的实例方法
        # 类当中的函数叫做方法:函数可以没有形参,而方法一定要有一个形参(对象本身self)
        # 默认的self形参后面可以自定义任何类型的形参:位置参数,不定长参数,默认参数等等......
        def sleep(self, time):
            print(f"睡觉,睡了{time}小时")
    
        def eat(self):
            print("吃饭")
    
        def play_games(self):
            print("玩游戏")
    
    
    # 如何创建一个对象(对象是通过类实例化的产物)
    # 通过人类Person创建一个对象,person1代表对象
    person1 = Person()
    # 通过人类Person创建一个对象,person2代表对象
    person2 = Person()
    # 实际对象是谁,那么谁就是self
    # 所有通过Person类创建的对象全部拥实例属性和实例方法
    

1.2.实例属性和实例方法的使用

  • 实例属性和实例方法的使用

    # 定义一个人类
    # 使用class关键字创建类:class关键字后面接类名(类名要符合标识符命名规则,并且一般推荐使用大驼峰命名法)
    # 在不发生继承的情况下,类后面的括号可写可不写
    class Person():
    
        # 类有一个名为 __init__() 的特殊方法(构造方法,有的称之为魔法方法),该方法在类实例化时会自动调用
        # 当对象一旦被创建,自动执行init构造方法里面的内容
        def __init__(self):
            # self代表对象本身
            # 特征:设置成类的实例属性
            # 对象的实例属性全部封装到init构造方法中
            self.name = "张三"
            self.age = 18
            self.sex = "男"
    
        # 行为:设置成类的实例方法
        # 类当中的函数叫做方法:函数可以没有形参,而方法一定要有一个形参(对象本身self)
        # 默认的self形参后面可以自定义任何类型的形参:位置参数,不定长参数,默认参数等等......
        def sleep(self, time):
            print(f"睡觉,睡了{time}小时")
    
        def eat(self):
            print("吃饭")
    
        def play_games(self):
            print("玩游戏")
    
    
    # 如何创建一个对象(对象是通过类实例化的产物)
    # 通过人类Person创建一个对象,person1代表对象
    person1 = Person()
    # 通过人类Person创建一个对象,person2代表对象
    person2 = Person()
    # 实际对象是谁,那么谁就是self
    # 所有通过Person类创建的对象全部拥实例属性和实例方法
    print(person1.name)  # 张三
    print(person1.age)  # 18
    print(person1.sex)  # 男
    # 通过对象调用实例方法
    # 对象名.方法名()
    person1.sleep(7)  # 睡觉,睡了7小时
    person1.eat()  # 吃饭
    person1.play_games()  # 玩游戏
    # 每一个对象都可以调用相同的实例方法(在内存里面是统一管理的区域)
    print(person2.name)  # 张三
    print(person2.age)  # 18
    print(person2.sex)  # 男
    person2.sleep(8)  # 睡觉,睡了8小时
    person2.eat()  # 吃饭
    person2.play_games()  # 玩游戏
    

1.3.自定义实例属性

  • 在实例方法当中使用实例属性

    class Person():
        # 因为创建对象时会自动调用init构造方法,那么如果需要创建对象的时候传递实参,需在init构造方法中就应该定义形参
        def __init__(self, name, age, sex):
            self.name = name
            self.age = age
            self.sex = sex
    
        def sleep(self, time):
            print(f"睡觉,睡了{time}小时")
    
        def eat(self):
            print("吃饭")
    
        def play_games(self):
            print("玩游戏")
    
        # 实例方法中可以使用实例属性
        def show(self):
            # 通过self.属性名进行使用
            print(f"姓名:{self.name},年龄:{self.age},性别:{self.sex}")
    
    
    person1 = Person("张三", 18, "男")
    person1.show()  # 姓名:张三,年龄:18,性别:男
    person2 = Person("李四", 20, "女")
    person2.show()  # 姓名:李四,年龄:20,性别:女
    

1.4.类属性和类方法的定义

  • 类属性和类方法的定义

    • 类里面定义的变量,就叫做类属性
    • 加上装饰器:@classmethod 的方法叫做类方法
    class Person():
        # 类里面定义的变量,就叫做类属性
        # name就是类属性
        name = "张三"
    
        def __init__(self):
            # 类里面并且在init构造方法里面定义的变量,叫做实例属性
            self.name1 = "李四"
    
        # 类方法的定义
        # 加上装饰器:@classmethod
        # 默认的第一个参数是cls:代表类名 Person = cls
        @classmethod
        def sleep(cls):
            print("类方法sleep被调用了")
    
        def eat(self):
            print("实例方法eat被调用了")
    

1.5.类属性和类方法的使用

  • 类属性和类方法的使用

    • 类只能调用类属性和类方法,不能使用实例方法和实例属性
    • 对象可以使用类属性和实例属性,类方法和实例方法
    class Person():
        name = "张三"
    
        def __init__(self):
            self.name1 = "李四"
    
        @classmethod
        def sleep(cls):
            print("类方法sleep被调用了")
    
        def eat(self):
            print("实例方法eat被调用了")
    
    
    # 类只能调用类属性和类方法,不能使用实例方法和实例属性
    # 类属性和类方法的使用
    # 通过类调用类属性:类名.属性名
    print(Person.name)  # 张三
    # 通过类调用类方法:类名.方法名()
    Person.sleep()  # 类方法sleep被调用了
    # 对象可以使用类属性和实例属性,类方法和实例方法
    # 创建对象
    person = Person();
    # 对象调用类属性
    print(person.name)  # 张三
    # 对象调用实例属性
    print(person.name1)  # 李四
    # 对象调用类方法
    person.sleep()  # 类方法sleep被调用了
    # 对象调用实例方法
    person.eat()  # 实例方法eat被调用了
    
  • 总结:实例属性和实例方法跟类属性类方法的区别

    • 类只能使用类属性和类方法
    • 对象可以使用类属性和实例属性以及类方法和实例方法

1.5.静态方法的定义及使用

  • 类中除了实例方法和类方法还有静态方法

  • 静态方法:类中的函数,第一个参数不是self也不是cls而可以没有参数

  • 类和对象都可以使用静态方法的使用

  • 静态方法的定义及使用

    class Person():
        name = "张三"
    
        def __init__(self):
            self.name = "张三"
    
        # 静态方法的定义
        # 静态方法:使用@staticmethod装饰器
        @staticmethod
        def play_games():
            print("我是play_games静态方法")
    
        # 类方法
        @classmethod
        def sleep(cls):
            print("类方法sleep被调用了")
    
        # 实例方法
        def eat(self):
            print("实例方法eat被调用了")
    
    
    # 类和对象都可以使用静态方法的使用
    # 类调用静态方法play_games 类名.静态方法名()
    Person.play_games()  # 我是play_games静态方法
    # 创建对象
    person = Person()
    # 对象调用静态方法play_games 对象名.静态方法名()
    person.play_games()  # 我是play_games静态方法
    

了解:类当中的方法可以使用装饰器@property变成属性

3.继承

  • 在程序当中,继承的描述是多个类之间的所属关系
  • 如果一个A类里面有分装好的属性和方法,那么B类继承A类之后,可以直接使用A类的所有属性和方法
  • 如果类与类之间发生了继承关系,那么A类就叫做父类(基类)B类叫做子类
  • 继承的类型有两种
    • 单继承
    • 多继承

3.1.单继承的使用

class Person():
    hobby = "钓鱼"

    def __init__(self):
        self.name = "张三"

    # 实例方法
    def eat(self):
        print("实例方法eat被调用了")

    # 类方法
    @classmethod
    def sleep(cls):
        print("类方法sleep被调用了")

    # 静态方法
    @staticmethod
    def play_games():
        print("静态方法play_games被调用了")


# Person2类继承了Person类(Person2是子类,Person是父类)
class Person2(Person):
    pass


# 根据Person2类创建对象
p1 = Person2()
# 使用Person类当中的类属性
print(p1.hobby)  # 钓鱼
# 使用Person类当中的实例属性
print(p1.name)  # 张三
# 使用Person类当中的类方法
p1.sleep()  # 类方法sleep被调用了
# 使用Person类当中的实例方法
p1.eat()  # 实例方法eat被调用了
# 使用Person类当中的静态方法
p1.play_games()  # 静态方法play_games被调用了

3.2.多继承的使用

  • 当父类有同名方法和同名属性(包括构造方法,魔法属性),会优先使用第一个继承的方法或者属性,不会重复执行也不会覆盖

  • 使用魔法属性 __mro__ 可以显示继承关系

    class Person():
        hobby = "钓鱼"
    
        def __init__(self):
            self.name = "张三"
    
        # 实例方法
        def eat(self):
            print("实例方法eat被调用了")
    
        # 类方法
        @classmethod
        def sleep(cls):
            print("类方法sleep被调用了")
    
        # 静态方法
        @staticmethod
        def play_games():
            print("静态方法play_games被调用了")
    
    
    class Person2():
        age = 18
    
        def __init__(self):
            self.height = 180
    
    
    # Person3类继承了Person类和Person2类
    class Person3(Person, Person2):
        pass
    
    
    # 根据Person3类创建对象
    p1 = Person3()
    # 使用Person类当中的类属性
    print(p1.hobby)  # 钓鱼
    # 使用Person类当中的实例属性
    print(p1.name)  # 张三
    # 使用Person类当中的类方法
    p1.sleep()  # 类方法sleep被调用了
    # 使用Person类当中的实例方法
    p1.eat()  # 实例方法eat被调用了
    # 使用Person类当中的静态方法
    p1.play_games()  # 静态方法play_games被调用了
    # 使用Person2类当中的类属性
    print(p1.age)  # 18
    # 使用Person2类当中的实例属性
    # 当父类有同名方法和同名属性(包括构造方法,魔法属性),会优先使用第一个继承的方法或者属性,不会重复执行也不会覆盖
    # print(p1.height)  # 执行报错 因为只会执行Person2类中的__init__构造方法,该方法中没有height实例属性
    # 通过魔法属性__mro__显示继承关系
    print(
        Person3.__mro__)  # (<class '__main__.Person3'>, <class '__main__.Person'>, <class '__main__.Person2'>, <class 'object'>)
    

总结:当子类方法和属性跟父类冲突时(属性和方法重名),优先使用子类重名的属性或者方法

3.3.子类调用父类同名属性和方法

通过内建函数super()可以调用父类的同名方法和属性

class Person():

    def eat(self):
        print("Person类中的实例方法eat被调用了")


class Person2():

    def eat(self):
        print("Person2类中的实例方法eat被调用了")


# Person3类继承了Person类和Person2类
class Person3(Person, Person2):

    def eat(self):
        # 通过内建函数super()可以调用父类的同名方法(使用父类的eat()方法)
        super().eat()


# 默认情况子类和父类属性方法同名优先使用子类属性和方法
p1 = Person3()
p1.eat()  # Person类中的实例方法eat被调用了

4.多态

  • 在程序设计中,鸭子类型是动态类型的一种风格。

  • 鸭子类型:当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子

  • 忽略对象的实际形态(状态),而是以胜任的方式去充当该类型。

  • 多态的概念:多态是指一类事物有多种形态,忽略对象的实际形态(状态),而是以胜任的方式去充当该类型。

    class Person():
    
        def __init__(self):
            self.name = "张三"
    
        def play_games(self):
            print("玩游戏")
    
    
    # 创建一个person对象
    person = Person()
    
    
    # 创建一个function函数
    def function():
        person.play_games()
        print(person.name)
    
    
    # 调用function函数
    function()
    

5.数据类装饰器

  • 数据类装饰器:可以对类进行装饰的装饰器

  • 自动为类创建很多特殊方法包括魔法方法,不需要手动的定义init直接使用,实例属性的另外一种定义格式

  • 数据类装饰器的使用:

    • 先导入 dataclasses 模块
    • 然后使用@dataclasses.dataclass
    import dataclasses  # 该模块在Python3.7版本之后才能使用
    
    
    # 数据类定义的变量可以被类方法和实例方法使用
    @dataclasses.dataclass
    class Person():
        name = "张三"
        # 实例属性的定义
        age: int = 18
    
        def show(self):
            print(f"我的年龄是:{self.age}岁")
    
        @classmethod
        def show2(cls):
            print(f"我的年龄是:{cls.age}岁")
    
    
    # 当创建对象传递实参,当数据被实例属性使用的时候会用用实参传递过来的值,类属性使用的时候会使用默认值
    person = Person(20)
    person.show()  # 我的年龄是:20岁
    person.show2()  # 我的年龄是:18岁
    

十五、装饰器

  • 装饰器的概念:可以在不修改原来代码的情况下(函数原有的功能),为装饰器的对象(原来的函数)增加新的功能或者添加限制条件以及帮助输出
  • 装饰器的常用的种类:
    • 函数的装饰器
    • 类的装饰器
    • 主要的设计模式:开放封闭的原则(对外扩展开发,对内关闭修改)

1.装饰器的定义

  • 装饰器本身是一个函数

  • 装饰器的返回值是一个函数的引用(函数名字)

  • 装饰器只能必须一定是一个形参(形参:用来接收函数的引用(接收函数的名字))

  • 核心的使用原则:装饰器是给已有的函数增加额外的功能,本质上是一个闭包函数

  • 装饰器的功能特点:

    • 不修改被装饰的函数原代码
    • 不修改已有函数的调用方式
    • 给已有函数增加额外功能(通过函数外部的装饰器实现)
    # 场景:去某平台购物,先登录才能添加商品到购物车
    def login(function):
        def login_in():
            print("进入登陆页面")
            print("输入账号密码点击登陆")
            print("正在进行登陆验证......")
            print("登陆成功")
            function()  # function函数的引用: function = shopping ---> function() = shopping()
    
        return login_in
    
    
    def shopping():
        print("买个iPhone15手机")
    
    
    # 这里的shopping变量可以随便命名
    shopping = login(shopping)  # shopping = login_in
    shopping()  # shopping() = login_in()
    
  • 代码执行流程

    在这里插入图片描述

2.装饰器的语法糖使用

  • Python提供了装饰器的精简的书写方式:语法糖格式

  • @装饰器的名字,通过语法糖完成对已有函数的装饰

  • 注意:装饰器要写在被装饰的函数定义的上面

    # 场景:去某平台购物,先登录才能添加商品到购物车
    def login(function):
        def login_in():
            print("进入登陆页面")
            print("输入账号密码点击登陆")
            print("正在进行登陆验证......")
            print("登陆成功")
            function()
    
        return login_in
    
    
    @login  # @login等同于shopping = login(shopping)
    def shopping():
        print("买个iPhone15手机")
    
    
    shopping()
    
  • 解释器在执行代码的时候遇到装饰器会先加载装饰器代码并执行

    # 会打印输出 "装饰器代码已经开始执行......"
    def login(function):
        def login_in():
            print("登陆成功")
            function()
    
        print("装饰器代码已经开始执行......")
        return login_in
    
    
    @login
    def shopping():
        print("买个iPhone15手机")
    

3.装饰器的使用场景

  • 统计一个函数的执行时间

  • 输出日志信息

  • 缓存处理

  • 实现路由

    统计一个函数的执行时间案例实现

    import time
    
    
    def get_time(function):
        def inner():
            begin = time.time()
            function()
            end = time.time()
            print(f"当前模块代码执行的时间是:{end - begin}秒")
    
        return inner
    
    
    @get_time
    def count():
        for i in range(1, 2000000):
            print(i)
    
    
    count()
    

4.带有参数的装饰器

  • 使用装饰器完成符号传递实参进行运算
def operation(flag):
    def out_funciton(fn):
        def inner_function(number1, number2):
            if flag == "+":
                print("您输入的符号是加号,正在努力计算结果......")
            elif flag == "-":
                print("您输入的符号是减号,正在努力计算结果......")
            elif flag == "*":
                print("您输入的符号是乘号,正在努力计算结果......")
            elif flag == "/":
                print("您输入的符号是除号,正在努力计算结果......")

            result = fn(number1, number2)
            return result

        return inner_function

    return out_funciton


@operation("+")
def add(a, b):
    return a + b


@operation("-")
def subtract(a, b):
    return a - b


@operation("*")
def multiply(a, b):
    return a * b


@operation("/")
def divide(a, b):
    return a / b


print(add(12, 30))
print(subtract(40, 20))
print(multiply(2, 9))
print(divide(9, 3))

5.带有参数的装饰器

十六、生成器反射

  • 使用了 yield 的函数被称为生成器

  • yield 是一个关键字,用于定义生成器函数,生成器函数是一种特殊的函数,可以在迭代过程中逐步产生值,而不是一次性返回所有结果。跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器

  • 当在生成器函数中使用 yield 语句时,函数的执行将会暂停,并将 yield 后面的表达式作为当前迭代的值返回。然后,每次调用生成器的 next() 方法或使用 for 循环进行迭代时,函数会从上次暂停的地方继续执行,直到再次遇到 yield 语句。这样,生成器函数可以逐步产生值,而不需要一次性计算并返回所有结果

  • 生成器当中可以有一个或者多个 yield 关键字

  • 调用一个生成器函数,返回的是一个迭代器对象

  • 生成器的定义及使用

    def function(number):
        while number > 0:
            yield number
            number -= 1
    
    
    # 创建生成器对象
    fun = function(5)
    
    # 通过迭代生成器获取值
    print(next(fun))  # 输出: 5
    print(next(fun))  # 输出: 4
    print(next(fun))  # 输出: 3
    
    # 使用 for 循环迭代生成器
    for value in fun:
        print(value)  # 输出: 2 1
    

十七、反射

  • 反射原理:通过字符串的名字(属性名,方法名),对实例对象进行修改和访问
  • 对类对对象进行属性和方法的操作(添加,删除,修改,查看)

1.通过反射添加或覆盖对象方法

  • 使用内建函数setattr()

    class A():
        def a(self):
            print("这是a方法")
    
        def b(self):
            print("这是b方法")
    
        def c(self):
            print("这是c方法")
    
    
    x = A()
    # 给x对象设置一个动态实例方法
    setattr(x, "d", print)
    x.d("通过d方法输出内容")
    
    setattr(x, "d", input)
    result = x.d("通过d方法获取用户输入内容:")
    print(result)
    
    # 覆盖
    setattr(x, "b", print)
    x.b("这是通过反射覆盖b方法")
    

2.通过反射删除

  • 使用内建函delattr()

    class A():
        def a(self):
            print("这是a方法")
    
        def b(self):
            print("这是b方法")
    
        def c(self):
            print("这是c方法")
    
    
    x = A()
    
    # 删除
    delattr(x, "a")
    

3.通过反射判断是否存在指定的方法

  • 使用内建函数hasattr()

    class A():
        def a(self):
            print("这是a方法")
    
        def b(self):
            print("这是b方法")
    
        def c(self):
            print("这是c方法")
    
    
    x = A()
    
    print(hasattr(x, "a"))  # True
    print(hasattr(x, "d"))  # False
    

4.通过反射读取方法

  • 使用内建函数getattr()

    class A():
        def a(self):
            print("这是a方法")
    
        def b(self):
            print("这是b方法")
    
        def c(self):
            print("这是c方法")
    
    
    x = A()
    
    for i in ["a", "b", "c"]:
        function = getattr(x, i)
        function()
    

十八、第三方库

  • 需要完成具体某个功能甚至整体功能会引入第三方库
  • 第三方库:模块,包,库

1.自动化测试使用的第三方库

  • 接口自动化:requests
  • web自动化:selenium
  • app自动化:appium
  • 测试报告:allure

2.第三方库的安装、卸载、查看

  • 安装

    pip install 第三方库的名字(包名)
    

    在这里插入图片描述

  • 卸载

    pip uninstall 第三方库的名字(包名)
    

    在这里插入图片描述

  • 查看

    #查看当前环境的包名字以及版本号
    pip list
    

    在这里插入图片描述

3.虚拟环境和本地环境的区分

  • 虚拟环境

在这里插入图片描述

虚拟环境里面的项目包第三方库都是独立的,不会跟本地冲突也不会有任何印象

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Redis 消息队列和发布订阅

文章目录 基本模式生产者消费者原理&模型redis实现java实现 发布者订阅者原理&模型redis实现java实现 stream模式原理&模型工作原理redis实现Java实现 选型外传 基本模式 采用redis 三种方案&#xff1a; ● 生产者消费者&#xff1a;一个消息只能有一个消费者 ●…

canvas绘制美队盾牌

查看专栏目录 canvas示例教程100专栏&#xff0c;提供canvas的基础知识&#xff0c;高级动画&#xff0c;相关应用扩展等信息。canvas作为html的一部分&#xff0c;是图像图标地图可视化的一个重要的基础&#xff0c;学好了canvas&#xff0c;在其他的一些应用上将会起到非常重…

Architecture Lab:预备知识2【汇编call/leave/ret指令、CS:APP练习4.4】

chap4的练习4.4&#xff08;page.255&#xff09;让用Y86-64实现rsum&#xff08;递归求数组元素之和&#xff09;&#xff0c;提示为&#xff1a;先得到x86-64汇编代码&#xff0c;然后转换成Y86-64的 这是rsum的c实现&#xff1a; long rsum(long *start, long count) {if …

1.环境部署

1.虚拟机安装redhat8系统 这个其实很简单&#xff0c;但是有一点小细节需要注意。 因为我的电脑是 16核心的&#xff0c;所以选择内核16&#xff0c;可以最大发挥虚拟机的性能 磁盘选择SATA&#xff0c;便于后期学习 将一些没用的设备移除 选择安装redhat 8 时间选择上海 选择…

php反序列化之pop链构造(基于重庆橙子科技靶场)

常见魔术方法的触发 __construct() //创建类对象时调用 __destruct() //对象被销毁时触发 __call() //在对象中调用不可访问的方法时触发 __callStatic() //在静态方式中调用不可访问的方法时触发 __get() //调用类中不存在变量时触发&#xff08;找有连续箭头的…

前端远原生js爬取数据的小案例

使用方法 注意分页的字段需要在代码里面定制化修改&#xff0c;根据你爬取的接口&#xff0c;他的业务规则改代码中的字段。比如我这里总条数叫total&#xff0c;人家的不一定。返回的数据我这里是data.rows&#xff0c;看看人家的是叫什么字段&#xff0c;改改代码。再比如我这…

【面试合集】说说微信小程序的发布流程?

面试官&#xff1a;说说微信小程序的发布流程&#xff1f; 一、背景 在中大型的公司里&#xff0c;人员的分工非常仔细&#xff0c;一般会有不同岗位角色的员工同时参与同一个小程序项目。为此&#xff0c;小程序平台设计了不同的权限管理使得项目管理者可以更加高效管理整个团…

【项目经验】详解Puppeteer入门及案例

文章目录 一.项目需求及Puppeteer是什么&#xff1f;二.Puppeteer注意事项及常用的方法1.注意事项2.常用的方法*puppeteer.launch&#xff08;&#xff09;**browser.newPage()**page.goto()**page.on(request&#xff0c;&#xff08;&#xff09;> {}&#xff09;**page.e…

(亲测可行)关于提高IDEA运行速度的方案

1.作者IDEA软件版本和计算机内存 Ultimate 2022.1.2版IDEA&#xff0c;计算机内存为12GB 2.修改配置以提高IDEA运行速度的误区-调高堆内存 很多文章会教调配置的内存&#xff0c;但大多是让你调高堆内存&#xff0c;比如会让你调高-Xms -Xmx &#xff0c;这两种对应的是最…

推荐几个Github高星GoLang管理系统

在Web开发领域&#xff0c;Go语言&#xff08;Golang&#xff09;以其高效、简洁、高并发等特性逐渐成为许多开发者的首选语言。有许多优秀的Go语言Web后台管理系统&#xff0c;这些项目星星众多&#xff0c;提供了丰富的功能和良好的代码质量。本文将介绍一些GitHub高星的GoLa…

32单片机RTC时间接续,掉电时间保存

1、实现思路 前提&#xff1a;首先要实现RTC掉电之后时间还能继续走&#xff0c;RTC电池是必要的 说明&#xff1a;设备第一次启动需要初始化配置RTC&#xff0c;但当二次启动再重新配置RTC会导致RTC计数器置零&#xff0c;所以传统的程序流程是不行的&#xff0c;我们需要知…

.sync详解记录(vue2)

.sync修饰符使用注意 在Vue.js中&#xff0c;.sync修饰符是一个非常有用的修饰符&#xff0c;它可以让父组件和子组件之间实现双向数据绑定。本文将详细介绍.sync修饰符的使用方法和原理。 什么是.sync修饰符&#xff1f; .sync修饰符是Vue.js提供的一种语法糖&#xff0c;它可…

transbigdata笔记:轨迹切片

1 方法介绍 在transbigdata笔记&#xff1a;轨迹停止点和行程提取-CSDN博客中&#xff0c;已经可以把轨迹点拆分成停止点和行程点&#xff0c;但是行程点只有起止位置&#xff0c;不包含行程轨迹信息为了进一步分析车辆的行驶轨迹&#xff0c;需要从每次行程的时间段中提取轨迹…

《2023年度程序员收入报告》 :旧金山位居第一,北京程序员中位数超60万元

2024年刚刚拉开序幕&#xff0c;备受瞩目的程序员薪资调研报告再度登场。由知名数据采集平台levels.fyi 搜集并整理了《2023年全球程序员收入报告》&#xff0c;为我们揭示了程序员最新的收入情况&#xff0c;其中有哪些值得关注的亮点呢&#xff1f; 行情向好&#xff0c;大多…

jmeter--8.加密传输

目录 1. Base64加密 2. MD5加密 3. SHA加密&#xff08;sha1\sha\sha224\sha256\sha384\sha512&#xff09; 4. RSA加密-公钥加密&#xff0c;私钥解密 1. Base64加密 1.1 在需要加密传输的接口下新增BeanShell 预处理程序&#xff0c;${username}可替换成value值&#xff…

Pycharm Terminal 无法激活conda环境

1.问题 Failed to activate conda environment. Please open Anaconda prompt, and run conda init powershell there. 这导致我们无法在Pycharm中使用conda命令 2.解决办法 修改为第二个&#xff0c;然后重启Terminal 再打开时发现已经是当前的conda环境

在客户端访问远程Linux服务器的私有IP地址的URL

文章目录 环境背景SSH tunnel和正向/反向代理步骤第一步第二步效果考一考 其它多次跳转另一种方法&#xff1a;正向代理 参考 环境 服务器&#xff1a;Ubuntu 22.04客户端&#xff1a;Mac 14.2.1 背景 在远程Linux服务器上搭建了minikube环境。minikube提供了dashboard功能&…

LLM:Scaling Laws for Neural Language Models (上)

论文&#xff1a;https://arxiv.org/pdf/2001.08361.pdf 发表&#xff1a;2020 摘要1&#xff1a;损失与模型大小、数据集大小以及训练所用计算量成比例&#xff0c;其中一些趋势跨越了七个量级以上。 2&#xff1a;网络宽度或深度等其他架构细节在很大范围内影响较小。3&…

mac pro “RESP.app”意外退出 redis desktop manager

文章目录 redis desktop manager下载地址提示程序含有恶意代码“RESP.app”意外退出解决办法&#xff1a;下载python3.10.并安装重新打开RESP如果还是不行&#xff0c;那么需要替换错误路径&#xff08;我的没用&#xff09;外传 最近在研究redis的消息&#xff0c;看到了strea…

mac查看maven版本报错:The JAVA_HOME environment variable is not defined correctly

终端输入mvn -version报错: The JAVA_HOME environment variable is not defined correctly, this environment variable is needed to run this program. Java环境变量的问题,打开bash_profile查看 open ~/.bash_profile export JAVA_8_HOME/Library/Java/JavaVirtualMachine…