【Python测试开发】Python高级

(以下笔记内容均来自bilibili@蜗牛学院)

一、异常的捕获和处理

1.1 什么是异常

  • 异常就是代码中的错误:语法错误、缩进错误、逻辑错误等。
  • 异常会中断代码的执行。

1.2 异常的处理

1.2.1 常见的异常

i = 8 / 0
print(i)

# 代码执行结果
Traceback (most recent call last):
  File "E:/软件测试学习/test/test02/demo01.py", line 1, in <module>
    i = 8 / 0
ZeroDivisionError: division by zero
print("这是模块文件的开始")
kameila
print("这是模块文件的结束")

# 代码执行结果:
Traceback (most recent call last):
  File "E:/软件测试学习/test/test02/demo02.py", line 2, in <module>
    kameila
NameError: name 'kameila' is not defined

1.2.2 异常捕获的语法

try:
    受保护的代码
except 异常类型:
    print("对异常的处理")

处理单个异常

try:
    i = 8 / 0
    print(i)
except ZeroDivisionError:
    print("零除数异常")

处理多个异常

try:
    i = 8 / 0
    print(i)
    kameila
# 一个except只能处理一种异常类型
except ZeroDivisionError:
    print("处理零除数异常")
except NameError:
    print("处理名字没有定义异常")

处理所有类型的异常

try:
    i = 8 / 0
    print(i)
    kameila
# Exception可以处理任意类型的异常
except Exception:
    # 异常的处理方式
    print("可以处理任意类型的异常")

获取异常的详细信息

try:
    i = 8 / 0
    print(i)
    kameila
# Exception可以处理任意类型的异常
except Exception as e:
    # 异常的处理方式
    print("可以处理任意类型的异常")
    # 打印异常的详细信息
    print(e)

获取所有异常类型的简写

# 导入traceback包
import traceback
try:
    i = 8 / 0
    print(i)
    kameila
# Exception可以处理任意类型的异常
# except后面不写Exception,也是捕获任意类型的异常,这是简写
# 简写的时候,在获取异常的详细信息的时候直接使用as 就不行了,要利用内置traceback模块获取内容
except:
    # 异常的处理方式
    print("可以处理任意类型的异常")
    #获取本次异常的报错信息
    print(traceback.format_exc())

代码执行结果:

可以处理任意类型的异常
Traceback (most recent call last):
  File "E:/软件测试学习/test/test02/demo01.py", line 4, in <module>
    i = 8 / 0
ZeroDivisionError: division by zero

1.3 else和finally语句

# 导入traceback包
import traceback
try:
    i = 8 / 0
    print(i)
    kameila
# Exception可以处理任意类型的异常
# except后面不写Exception,也是捕获任意类型的异常,这是简写
# 简写的时候,在获取异常的详细信息的时候直接使用as 就不行了,要利用内置traceback模块获取内容
except:
    # 异常的处理方式
    print("可以处理任意类型的异常")
    #获取本次异常的报错信息
    print(traceback.format_exc())
# try下面缩进的代码没有异常,才会执行else语句下的语句块
else:
    print("这里是else语句")
# finally语句必须在else语句的后面,无论try语句下面缩进的代码有没有问题,都会执行finally后的内容
finally:
    print("这里是finally语句")

代码执行结果:

可以处理任意类型的异常
Traceback (most recent call last):
  File "E:/软件测试学习/test/test02/demo01.py", line 4, in <module>
    i = 8 / 0
ZeroDivisionError: division by zero

这里是finally语句

1.4 异常的就近捕获原则

def f1():
    try:
        print("*********f1开始********")
        kameila
        print("*********f1结束********")
    except:
        print("f1捕获了!!!")
def f2():
    try:
        print("*********f2开始********")
        f1()
        print("*********f2结束********")
    except:
        print("f2捕获了!!!")
def f3():
    try:
        print("*********f3开始********")
        f2()
        print("*********f3结束********")
    except:
        print("f3捕获了!!!")
f3()

代码执行结果:

*********f3开始********
*********f2开始********
*********f1开始********
f1捕获了!!!
*********f2结束********
*********f3结束********

1.5 异常的抛出

# 村
def f1():
    try:
        print("*********f1开始********")
        kameila
        print("*********f1结束********")
    except:
        # 抛出异常
        raise
# 镇
def f2():
    try:
        print("*********f2开始********")
        f1()
        print("*********f2结束********")
    except:
        raise
# 县
def f3():
    try:
        print("*********f3开始********")
        f2()
        print("*********f3结束********")
    except:
        print("f3捕获了!!!")
       
f3()

代码执行结果:

*********f3开始********
*********f2开始********
*********f1开始********
f3捕获了!!!

二、OS模块

  • OS模块是Python的内置函数,无需下载安装,使用的时候直接导入OS包即可import os
import os
# Windows操作系统返回的是 nt “Microsoft Windows NT”
# 当前系统的内核
print(os.name)
# 查看系统的环境变量
print(os.environ['JAVA_HOME'])
for root, dirs, files in os.walk(".", topdown=False):
    '''
    root:路径
    dirs :[]  文件夹
    files : 文件
    '''
    print(root)
    print(dirs)
    print(files)
    print("***********************")
# 列出某个目录下的文件(文件名)或者文件夹
print(os.listdir('F:\桌面壁纸'))
# 删除目录(文件夹)
os.rmdir("F:\桌面壁纸\新建文件夹")
# 删除文件
os.remove("F:\桌面壁纸\新建 XLS 工作表.xls")
# 对文件进行重命名
os.rename(r"F:\桌面壁纸\cRwPlRY.jpg",r"F:\桌面壁纸\4.jpg")
# 创建目录
os.mkdir("F:\桌面壁纸\hello")
# 获取当前目录 (显示的是绝对路径)
print(os.getcwd())
# 路径的拼接
p1 = os.path.join(r"F:\视频","python","str1.py")
print(p1)
# 将路径分隔符号// 转换为\
new_path = os.path.abspath(r"F://webtest//autotestpytest//outFile//log")
print(new_path)
# 输出当前路径的最底层目录
a = os.path.basename(r'F:\桌面壁纸\hello')
print(a)
#将传入的路径以最后一个分隔符,进行分割,形成一个元组
('F:\\webtest\\autotestpytest', 'libs')
c = os.path.split(r'F:\webtest\autotestpytest\libs')
print(c)
#用于判断传入的路径是否存在 , 存在则返回true 不存在则返回false
print(os.path.exists(r"D:\tools12"))
#判断是否为绝对路径,如果是绝对路径则返回TRUE ,否则返回false
print(os.path.isabs(r'D:\tools'))
#判断传入的是不是文件
print(os.path.isfile(r'D:\tools\WebStorm 2020.1.1.rar'))
# 判断传入的是不是路径
print(os.path.isdir(r"D:\tools"))

三、random

import random
# 生成一个指定范围的随机整数,整体是闭区间
print(random.randint(1, 2))

# 随机从列表中取出一个元素
names = ["卡梅拉", "卡梅利多", "卡门", "皮迪克"]
print(random.choice(names))

# 随机从列表中取出三个值
print(random.sample(names, 3))

# 生成0-1之间的随机小数
print(random.random())

# 生成一个指定范围的随机整数,左闭右开区间
print(random.randrange(1, 4))

# 生成一个指定范围内的随机浮点数
print(random.uniform(12, 33))

代码执行结果:

1
皮迪克
['皮迪克', '卡门', '卡梅拉']
0.9251579510451422
3
18.440344059549698

四、时间周期模块

导入time模块

import time
# 从1970年 0:0:0截止到当前时间过去的秒数
print(f'从1970年 0:0:0截止到当前时间过去的秒数是:{time.time()}')

# 返回当前时间,返回的内容可以当做一个元组进行处理
"""
(tm_year=2023, tm_mon=8, tm_mday=28, tm_hour=17, tm_min=7, tm_sec=44, tm_wday=0, tm_yday=240, tm_isdst=0)
tm_year :年
tm_mon :月(1-12)
tm_mday :日(1-31)
tm_hour :时(0-23)
tm_min :分(0-59)
tm_sec :秒(0-59)
tm_wday :星期几(0-6,0表示周日)
tm_yday :一年中的第几天(1-366)
tm_isdst :是否是夏令时(默认为-1)
"""

t1 = time.localtime()
print(f'当前时间表示为:{t1}')
# 取出当前年月日
print(f'当前年份为:{t1[0]}{t1[1]}{t1[2]}日')

# 休眠  代码执行到这一行停顿3秒后继续往下执行  单位是秒
print("****************开始**********************")
time.sleep(3)
print("****************结束**********************")

# 输出时间格式化
"""
%a  本地星期名称的简写(如星期四为Thu)      
%A  本地星期名称的全称(如星期四为Thursday)      
%b  本地月份名称的简写(如八月份为agu)    
%B  本地月份名称的全称(如八月份为august)       
%c  本地相应的日期和时间的字符串表示(如:15/08/27 10:20:06)       
%d  一个月中的第几天(01 - 31)  
%f  微秒(范围0.999999)    
%H  一天中的第几个小时(24小时制,00 - 23)       
%I  第几个小时(12小时制,0 - 11)       
%j  一年中的第几天(001 - 366)     
%m  月份(01 - 12)    
%M  分钟数(00 - 59)       
%p  本地am或者pm的相应符      
%S  秒(00 - 60)    
%U  一年中的星期数。(00 - 53星期天是一个星期的开始。)第一个星期天之    前的所有天数都放在第0周。     
%w  一个星期中的第几天(0 - 6,0是星期天)    
%W  和%U基本相同,不同的是%W以星期一为一个星期的开始。    
%x  本地相应日期字符串(如15/08/01)     
%X  本地相应时间字符串(如08:08:10)     
%y  去掉世纪的年份(00 - 99)两个数字表示的年份       
%Y  完整的年份(4个数字表示年份)
%z  与UTC时间的间隔(如果是本地时间,返回空字符串)
%Z  时区的名字(如果是本地时间,返回空字符串)       
%%  ‘%’字符  
"""
print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))

代码执行结果:

19700:0:0截止到当前时间过去的秒数是:1693215227.6942265
当前时间表示为:time.struct_time(tm_year=2023, tm_mon=8, tm_mday=28, tm_hour=17, tm_min=33, tm_sec=47, tm_wday=0, tm_yday=240, tm_isdst=0)
当前年份为:2023828****************开始**********************
****************结束**********************
2023-08-28 17:33:50

Process finished with exit code 0

导入datetime模块

import datetime
# 获取当前时间
gettime = datetime.datetime.now()
print(f'当前时间为:{gettime}')

# 格式化输出
print(f'格式化输出的时间为:{gettime.strftime("%Y-%m-%d %H:%M:%S")}')

代码输出结果是:

当前时间为:2023-08-28 17:40:04.226769
格式化输出的时间为:2023-08-28 17:40:04

Process finished with exit code 0

五、面向对象

以下均使用该案例内容:

5.1 类的定义

语法:

# 如果没有要继承的类,类名后面的()可以不写【不写其实是默认继承的object类】
class 类名():
    属于该类的属性和行为

5.2 属性的定义

  • 属性分类:静态属性、实例属性
    • 静态属性:实例对象所共有的属性
    • 实例属性:每一个实例对象所特有的属性
  • self:指的是实例化对象本身
  • 要产生对象,其实就是根据类进行实例化而已
class Tiger():
    # 名称:静态属性
    name = '老虎'
    # 体重:实例属性
    def __init__(self, weight):
        # 属性的定义跟变量类似
        self.weight = weight
        # 输出老虎的体重
        print(self.weight)
# 在类的实例化的时候,会执行初始化方法init
# 要产生对象,其实就是根据类进行实例化而已
# 实例化对象,并传入必填参数
t1 = Tiger(200)

# 访问静态属性:通过
# 方式一:通过 【实例化对象名.属性名】
print(f'通过【实例化对象名.属性名】输出名字:{t1.name}')
# 方式二通过 【类名.属性名】
print(f'通过【类名.属性名】输出名字:{Tiger.name}')

# 访问实例属性
print(f'访问实例属性 输出体重:{t1.weight}')

代码执行结果:

200
通过【实例化对象名.属性名】输出名字:老虎
通过【类名.属性名】输出名字:老虎
访问实例属性 输出体重:200

Process finished with exit code 0

5.3 方法的定义

  • 方法对应的就是行为
  • 方法的分类:静态方法、实例方法、类方法
    • 静态方法:所有实例对象所共有的方法。静态方法中只能访问静态属性
    • 实例方法:每一个实例对象所独有的方法;实例方法名后面的括号中的self指的是实例化对象本身。实例方法中可以访问实例属性和静态属性
    • 类方法:针对整个类而言,类方法中可以访问静态属性
  • 判断哪个方法要定义成哪种类型?
    • 根据是否要操作实例属性做判断;如果方法要使用实例属性,则是实例方法
# 定义类
class Tiger():
    # 名称:静态属性
    name = '老虎'
    # 体重:实例属性
    def __init__(self, weight):
        # 属性的定义跟变量类似
        self.weight = weight
        # 输出老虎的体重
        print(self.weight)

    # 判断用实例方法、类方法、静态方法的哪一种?如果方法要使用实例属性,则必然是实例方法
    # 实例方法:喂食
    def eat(self, food):
        # 判断
        if food == 'meet':
            print("喂对了!动物的体重加10斤!!")
            # 访问实例属性
            self.weight += 10
        else:
            print("喂不了!动物的体重减10斤!!")
            self.weight -= 10

    # 实例方法:叫声
    def houjiao(self):
        print(f"{Tiger.name}:wow!wow!")
        # 每叫一次,动物的体重减5斤
        self.weight -= 5

    # 静态方法:跳跃
    @staticmethod
    def jump():
        print(f'{Tiger.name}会跳跃')

    # 类方法
    @classmethod
    def a(cls):
        # 在类方法中访问静态属性有两种方法:1、类名.静态属性名 2、cls.静态属性名(cls指的就是这个类)
        print("这里是类方法!")


# 实例化对象
t1 = Tiger(200)
# 访问实例化方法
t1.houjiao()
t1.eat("meet")
# 访问静态方法2种: 1、实例对象名.静态方法名  2、类名.静态方法名
t1.jump()
Tiger.jump()
# 访问类方法2种: 1、 实例对象名.静态方法名  2、类名.静态方法名
t1.a()
Tiger.a()

代码执行结果:

200
老虎:wow!wow!
喂对了!动物的体重加10斤!!
老虎会跳跃
老虎会跳跃
这里是类方法!
这里是类方法!

Process finished with exit code 0

5.4 对象的组合

  • 对象的组合:将小对象当做大对象的一个属性传入即可
    该包下的另一个Python文件定义羊类
# 定义羊类
class Sheep():
    # 静态属性
    name = "羊"

    # 实例属性
    def __init__(self, weight):
        self.weight = weight
        print(f"此时{self.name}的体重为{self.weight}")

    # 实例方法:喂食
    def feed(self, food):
        if food == "grass":
            self.weight += 10
            print(f"喂对了,体重加10斤!此时{self.name}的体重为{self.weight}斤!")
        else:
            self.weight -= 10
            print(f"喂错了,体重减10斤!此时{self.name}的体重为{self.weight}斤!")

    # 实例方法:叫声
    def roar(self):
        self.weight -= 5
        print(f'羊叫,体重减5斤:{self.weight}')

# 实例化对象
s1 = Sheep(100)
# 调用喂食方法
s1.feed("grass")

组合类

# 导入sheep类
from test03.demo02 import Sheep
# 定义类
class Tiger():
    # 名称:静态属性
    name = '老虎'
    # 体重:实例属性
    def __init__(self, weight):
        # 属性的定义跟变量类似
        self.weight = weight
        # 输出老虎的体重
        print(self.weight)

    # 判断用实例方法、类方法、静态方法的哪一种?如果方法要使用实例属性,则必然是实例方法
    # 实例方法:喂食
    def feed(self, food):
        # 判断
        if food == 'meet':
            print("喂对了!动物的体重加10斤!!")
            # 访问实例属性
            self.weight += 10
        else:
            print("喂不了!动物的体重减10斤!!")
            self.weight -= 10

    # 实例方法:叫声
    def roar(self):
        print(f"{Tiger.name}:wow!wow!")
        # 每叫一次,动物的体重减5斤
        self.weight -= 5

    # 静态方法:跳跃
    @staticmethod
    def jump():
        print(f'{Tiger.name}会跳跃')

    # 类方法
    @classmethod
    def a(cls):
        # 在类方法中访问静态属性有 两种方法:1、类名.静态属性名 2、cls.静态属性名(cls指的就是这个类)
        print("这里是类方法!")
# 房间类
class Room():
    # 实例属性:房间号、房间内的动物
    def __init__(self, num, animal):
        self.num = num
        self.animal = animal

# 实例化一只羊
s1 = Sheep(100)
# 实例化2号房间
r2 = Room(2, s1)

# 访问羊对象的静态属性
print(f'访问羊的静态属性:{r2.animal.name}')
# 访问羊对象的实例方法
print(f'访问羊的实例方法:{r2.animal.roar(100)}')


# 实例化老虎对象
t1 = Tiger(200)

# 实例化房间
r1 = Room(1, t1)

# 访问1号房间内老虎的静态属性
print(f'访问1号房间内老虎的静态属性:{r1.animal.name}')

# 访问1号房间内老虎的实例属性
print(f'访问1号房间内老虎的实例属性:{r1.animal.weight}')

# 访问1号房间内老虎的静态方法
print(f'访问1号房间内老虎的静态方法:{r1.animal.jump()}')

# 访问1号房间内老虎的实例方法
print(f'访问1号房间内老虎的实例方法:{r1.animal.feed("grass")}')

# 访问1号房间内老虎的类方法
print(f'访问1号房间内老虎的类方法:{r1.animal.a}')

代码执行结果:
在这里插入图片描述

5.5 继承

  • 子类继承父类,一个父类可以有多个子类,一个子类可以继承多个父类
  • 子类继承了父类的一切属性和方法

语法实现:

# 继承
# 老虎:东北虎、华南虎、西伯利亚虎
# 定义东北虎类,继承老虎类
class NeTiger(Tiger):
    def __init__(self, weight):
        Tiger.__init__(self, weight)

继承实现:

# 定义类
class Tiger():
    # 名称:静态属性
    name = '老虎'
    # 体重:实例属性
    def __init__(self, weight):
        # 属性的定义跟变量类似
        self.weight = weight
        # 输出老虎的体重
        print(self.weight)

    # 判断用实例方法、类方法、静态方法的哪一种?如果方法要使用实例属性,则必然是实例方法
    # 实例方法:喂食
    def feed(self, food):
        # 判断
        if food == 'meet':
            print("喂对了!动物的体重加10斤!!")
            # 访问实例属性
            self.weight += 10
        else:
            print("喂不了!动物的体重减10斤!!")
            self.weight -= 10

    # 实例方法:叫声
    def roar(self):
        print(f"{Tiger.name}:wow!wow!")
        # 每叫一次,动物的体重减5斤
        self.weight -= 5

    # 静态方法:跳跃
    @staticmethod
    def jump():
        print(f'{Tiger.name}会跳跃')

    # 类方法
    @classmethod
    def a(cls):
        # 在类方法中访问静态属性有 两种方法:1、类名.静态属性名 2、cls.静态属性名(cls指的就是这个类)
        print("这里是类方法!")

# 继承
# 老虎:东北虎、华南虎、西伯利亚虎
# 定义东北虎类,继承老虎类
class NeTiger(Tiger):
    def __init__(self, weight):
        Tiger.__init__(self, weight)

# 实例化东北虎对象
net1 = NeTiger(220)

# 访问静态属性
print(f'访问父类Tiger的静态属性:{net1.name}')

# 访问实例方法
print(f'访问父类Tiger的实例方法:{net1.roar()}')

代码执行结果:

220
访问父类Tiger的静态属性:老虎
老虎:wow!wow!
访问父类Tiger的实例方法:None

Process finished with exit code 0

5.6 重定义

  • 子类继承父类后,觉得父类的某个方法不能满足自己,就需要对该方法进行重定义(在子类中将需要修改的父类方法内容重新按照自己的需求写一遍)
  • 重定义方法后,对于父类的方法的改变只限于该子类
# 定义类
class Tiger():
    # 名称:静态属性
    name = '老虎'
    # 体重:实例属性
    def __init__(self, weight):
        # 属性的定义跟变量类似
        self.weight = weight
        # 输出老虎的体重
        print(self.weight)

    # 判断用实例方法、类方法、静态方法的哪一种?如果方法要使用实例属性,则必然是实例方法
    # 实例方法:喂食
    def feed(self, food):
        # 判断
        if food == 'meet':
            print("喂对了!动物的体重加10斤!!")
            # 访问实例属性
            self.weight += 10
        else:
            print("喂不了!动物的体重减10斤!!")
            self.weight -= 10

    # 实例方法:叫声
    def roar(self):
        print(f"{Tiger.name}:wow!wow!")
        # 每叫一次,动物的体重减5斤
        self.weight -= 5

    # 静态方法:跳跃
    @staticmethod
    def jump():
        print(f'{Tiger.name}会跳跃')

    # 类方法
    @classmethod
    def a(cls):
        # 在类方法中访问静态属性有 两种方法:1、类名.静态属性名 2、cls.静态属性名(cls指的就是这个类)
        print("这里是类方法!")

# 继承
# 老虎:东北虎、华南虎、西伯利亚虎
# 定义东北虎类,继承父类Tiger
class NeTiger(Tiger):
    def __init__(self, weight):
        Tiger.__init__(self, weight)

# 实例化东北虎对象
net1 = NeTiger(220)

# 访问静态属性
print(f'访问父类Tiger的静态属性:{net1.name}')
# 访问实例方法
print(f'访问父类Tiger的实例方法:{net1.roar()}')

# 定义华南虎,继承父类Tiger
class ScTiger(Tiger):
    # 重定义静态属性
    name = "华南虎"
    def __init__(self, weight):
        Tiger.__init__(self, weight)

    # 重定义静态方法
    @staticmethod
    def jump():
        print(f'这里是重定义的静态方法:{ScTiger.name}会跳跃')

sct1 = ScTiger(180)
sct1.jump()

代码执行结果:

220
访问父类Tiger的静态属性:老虎
老虎:wow!wow!
访问父类Tiger的实例方法:None
180
这里是重定义的静态方法:华南虎会跳跃

Process finished with exit code 0

5.7 面向对象的三大特征

  • 继承
  • 封装
  • 多态
  • 如果有第四大特征:抽象
import time
import random


# 老虎类
class Tiger():
    # 名称:静态属性
    name = '老虎'

    # 体重:实例属性
    def __init__(self, weight):
        # 属性的定义跟变量类似
        self.weight = weight
        # 输出老虎的体重
        # print(f'老虎的初始体重为:{self.weight}')

    # 判断用实例方法、类方法、静态方法的哪一种?如果方法要使用实例属性,则必然是实例方法
    # 实例方法:喂食
    def feed(self, food):
        # 判断
        if food == 'meat':
            print("喂对了!动物的体重加10斤!!此时{self.name}的体重为{self.weight}斤!")
            # 访问实例属性
            self.weight += 10
        else:
            print("喂错了!动物的体重减10斤!!此时{self.name}的体重为{self.weight}斤!")
            self.weight -= 10

    # 实例方法:叫声
    def roar(self):
        print("wow!wow!wow!")
        # 每叫一次,动物的体重减5斤
        self.weight -= 5

    # # 静态方法:跳跃
    # @staticmethod
    # def jump():
    #     print(f'{Tiger.name}会跳跃')
    #
    # # 类方法
    # @classmethod
    # def a(cls):
    #     # 在类方法中访问静态属性有 两种方法:1、类名.静态属性名 2、cls.静态属性名(cls指的就是这个类)
    #     print("这里是类方法!")


# 定义羊类
class Sheep():
    # 静态属性
    name = "羊"

    # 实例属性
    def __init__(self, weight):
        self.weight = weight
        # print(f"此时{self.name}的体重为{self.weight}")

    # 实例方法:喂食
    def feed(self, food):
        if food == "grass":
            self.weight += 10
            print(f"喂对了,体重加10斤!此时{self.name}的体重为{self.weight}斤!")
        else:
            self.weight -= 10
            print(f"喂错了,体重减10斤!此时{self.name}的体重为{self.weight}斤!")

    # 实例方法:嚎叫
    def roar(self):
        print("mie!mie!mie!")
        # 每嚎叫一次,体重减5斤
        self.weight -= 5


# 定义房间类
class Room():
    def __init__(self, num, animal):
        # 房间号
        self.num = num
        # 房间中的动物
        self.animal = animal


# 定义一个列表,用来存放生成的10个Room对象
rooms = []

# 生成10个Room对象
# r为 1-10 十个房间号
for i in range(1, 11):
    flag = random.randint(0, 1)
    if flag == 0:
        a = Tiger(200)
    else:
        a = Sheep(100)
        # 实例化Room对象,添加进房间列表
    rooms.append(Room(i, a))

# 获取游戏开始时间
print("游戏即将开始。。。")
start_time = time.time()
while True:
    end_time = time.time()
    if end_time - start_time > 20:
        print("游戏即将结束!!!")
        # 输出游戏结束时房间内的动物信息
        for r in rooms:
            print(f"第{r.num}号房间的动物是{r.animal.name},目前体重是{r.animal.weight}")
        break
    # 随机弹出一个房间
    r1 = random.choice(rooms)
    print(f'本次弹出的是{r1.num}号房间')
    # 选择是否要敲门
    f = input('请选择是否敲门:输入y:')
    if f == 'y':
        # 调用敲门的实例方法
        r1.animal.roar()
    # 不需要敲门,则可以直接喂食
    food = input("请输入投喂的食物:meat or grass?")
    r1.animal.feed(food)

代码执行结果:

游戏即将开始。。。
本次弹出的是2号房间
请选择是否敲门:输入y:y
mie!mie!mie!
请输入投喂的食物:meat or grass?grass
喂对了,体重加10斤!此时羊的体重为105斤!
本次弹出的是10号房间
请选择是否敲门:输入y:y
wow!wow!wow!
请输入投喂的食物:meat or grass?meat
喂对了!动物的体重加10斤!!此时{self.name}的体重为{self.weight}斤!
本次弹出的是10号房间
请选择是否敲门:输入y:
请输入投喂的食物:meat or grass?meat
喂对了!动物的体重加10斤!!此时{self.name}的体重为{self.weight}斤!
游戏即将结束!!!
第1号房间的动物是羊,目前体重是1002号房间的动物是羊,目前体重是1053号房间的动物是老虎,目前体重是2004号房间的动物是羊,目前体重是1005号房间的动物是羊,目前体重是1006号房间的动物是羊,目前体重是1007号房间的动物是羊,目前体重是1008号房间的动物是老虎,目前体重是2009号房间的动物是老虎,目前体重是20010号房间的动物是老虎,目前体重是215

Process finished with exit code 0

5.8 【案例】:游戏人生程序

  1. 创建三个游戏任务,分别是:
  • 马国宝,男,69,初始战斗力(combatpower)1000
  • 闫芳,女,55,初始战斗力2000
  • 魏雷,男,50,初始战斗力2500
  1. 游戏场景,分别是:
  • 草丛战斗(grass fight),消耗200战斗力
  • 自我修炼(cultvation),增加100战斗力
  • 多人游戏(multiplayer game),消耗500战斗力

代码实现:

# 创建人物类,如果没有要继承的类,类名后面的()可以不加
class Person:
    # 实例属性:姓名、性别、年龄、战斗力
    def __init__(self, name, sex, age, combatpower):
        self.name = name
        self.sex = sex
        self.age = age
        self.combatpower = combatpower

    # 实例属性
    def grass_fight(self):
        print("————草丛战斗————")
        # 消耗战斗力200
        self.combatpower -= 200

    def cultivation(self):
        print("————自我修炼————")
        # 增加战斗力100
        self.combatpower += 100

    def multiplayer_game(self):
        print("————多人游戏————")
        # 消耗战斗力500
        self.combatpower -= 500


# 实例化三个游戏人物
p1 = Person('马国宝', '男', '69', 1000)
p2 = Person('闫芳', '女', '55', 2000)
p3 = Person('魏雷', '男', '50', 2500)

# 访问实例方法
p1.grass_fight()
print(f"进行草丛战斗后,马国宝的战斗力为{p1.combatpower}")
p2.cultivation()
print(f"进行草丛战斗后,闫芳的战斗力为{p2.combatpower}")
p3.multiplayer_game()
print(f"进行草丛战斗后,魏雷的战斗力为{p3.combatpower}")

代码执行结果:

————草丛战斗————
进行草丛战斗后,马国宝的战斗力为800
————自我修炼————
进行草丛战斗后,闫芳的战斗力为2100
————多人游戏————
进行草丛战斗后,魏雷的战斗力为2000

Process finished with exit code 0

六、多线程

6.1 进程和线程

  • 每个进程里面至少包含一个线程(主线程)
  • 线程是操作系统创建的,用来控制代码执行的数据结构
  • 线程就像代码的执行许可证
    单线程程序
  • 主线程的入口就是代码的开头
  • 主线程顺序往下执行,直到所有的代码都执行完

6.2 创建线程

语法1:只有入口函数时

# 导入包
from threading import Thread

# 创建线程
# target 指定线程开始执行的代码,只写函数名即可,不用写后面的括号(写括号是调用函数)
th1 = Thread(target=f1)

# 启动线程
th1.start()

语法2:入口函数带参数时

# 导入包
from threading import Thread

# 创建线程
# target 指定线程开始执行的代码,只写函数名即可,不用写后面的括号(写括号是调用函数)
th1 = Thread(target=f1, )

# 启动线程
th1.start()

代码实现(入口函数不带参数):

print("################主线程开始################")
from threading import Thread
from time import sleep

# 创建线程
def f1():
    print("###############f1开始#################")
    sleep(3)
    print("###############f1结束#################")

def f2():
    print("###############f2开始#################")
    sleep(5)
    print("###############f2结束#################")
# 创建线程
# target 指定线程开始执行的代码,只写函数名即可,不用写后面的括号(写括号是调用函数)
th1 = Thread(target=f1)
th2 = Thread(target=f2)
# 启动线程
th1.start()
th2.start()
print("################主线程结束################")

代码执行结果:

################主线程开始################
###############f1开始#################
###############f2开始#################
################主线程结束################
###############f1结束#################
###############f2结束#################

Process finished with exit code 0

代码实现:(入口函数带参数)

print("################主线程开始################")
from threading import Thread
from time import sleep

# 创建线程
# 方法中有必填参数时
def f1(s):
    print("###############f1开始#################")
    sleep(s)
    print("###############f1结束#################")

def f2(s):
    print("###############f2开始#################")
    sleep(s)
    print("###############f2结束#################")
# 创建线程
# target 指定线程开始执行的代码,只写函数名即可,不用写后面的括号(写括号是调用函数)
# args 后面的参数是以元组的方式传入
th1 = Thread(target=f1, args=(3,))
th2 = Thread(target=f2, args=(5,))
# 启动线程
th1.start()
th2.start()
print("################主线程结束################")

代码执行结果:

################主线程开始################
###############f1开始#################
###############f2开始#################
################主线程结束################
###############f1结束#################
###############f2结束#################

Process finished with exit code 0

6.3 主线程等待

  • 主线程等待子线程全部执行完毕后再继续执行

语法:

# 设置等待
th1.join()

代码实现:

print("################主线程开始################")
from threading import Thread
from time import sleep

# 创建线程
# 方法中有必填参数时
def f1(s):
    print("###############f1开始#################")
    sleep(s)
    print("###############f1结束#################")

def f2(s):
    print("###############f2开始#################")
    sleep(s)
    print("###############f2结束#################")
# 创建线程
# target 指定线程开始执行的代码,只写函数名即可,不用写后面的括号(写括号是调用函数)
# args 后面的参数是以元组的方式传入
th1 = Thread(target=f1, args=(2,))
th2 = Thread(target=f2, args=(4,))
# 启动线程
th1.start()
th2.start()

# 设置等待
th1.join()
th2.join()

print("################主线程结束################")

代码执行结果:

################主线程开始################
###############f1开始#################
###############f2开始#################
###############f1结束#################
###############f2结束#################
################主线程结束################

Process finished with exit code 0

6.4 共享对象

  • 多个子线程不允许同时执行时,需要给子线程加锁

语法:

# 导入包
from threading import Lock

# 申请一把锁
l1 = Lock()
# 加锁
l1.acquire()
# 释放锁
l1.release()

代码实现:

from threading import Thread, Lock
from time import sleep

# 存储支付宝账号余额
zhifubao = {
    'zhangsan':  10000,
    'lisi':  5000,
    'wanger':  3000,
    'xiaohong':  3000,
        }
# 申请一把锁
zhifubao_lock = Lock()

# 线程1:滴滴打车处理,参数是用户账户和扣款金额
def didi_pay(account, amount):
    print("*t1:即将开始操作")

    # 加锁
    zhifubao_lock.acquire()

    balance = zhifubao[account]
    # 下面的sleep(2)表示一些处理过程需要花上2秒钟
    sleep(2)
    print("*t1:下面开始扣款")
    # 将扣款后的支付宝余额更新到原来的字典中
    zhifubao[account] = balance - amount

    # 释放锁
    zhifubao_lock.release()

# 线程2:余额宝赚取利息,参数是用户账户和利息金额
def yuebao_pay(account, amount):
    print("*t2:即将开始操作")

    # 加锁
    zhifubao_lock.acquire()

    balance = zhifubao[account]
    # 下面的sleep(2)表示一些处理过程需要花上2秒钟
    sleep(2)
    print("*t2:获取利息")
    # 将得到利息后的支付宝余额更新到原来的字典中
    zhifubao[account] = balance + amount

    # 释放锁
    zhifubao_lock.release()

# 分别创建两个线程
th1 = Thread(target=didi_pay, args=('zhangsan', 2000))
th2 = Thread(target=yuebao_pay, args=('zhangsan', 2000))

# 启动线程
th1.start()
th2.start()

# 设置等待
th1.join()
th2.join()

# 输出账户余额
print("________________________________________________________________")
print(f"zhangsan的账户余额为:{zhifubao['zhangsan']}")

代码执行结果:

*t1:即将开始操作
*t2:即将开始操作
*t1:下面开始扣款
*t2:获取利息
________________________________________________________________
zhangsan的账户余额为:10000

Process finished with exit code 0

6.5 【案例】:给房间中的羊和老虎喂食(优化版)

在这里插入图片描述

  • 优化内容
    • 如果未在键盘输入“是否敲门/喂食的食物”,也不影响游戏时间继续运行,游戏给定时长一经达到,就会自动退出该模块文件
import time
import random
from threading import Thread
import os

# 老虎类
class Tiger():
    # 名称:静态属性
    name = '老虎'

    # 体重:实例属性
    def __init__(self, weight):
        # 属性的定义跟变量类似
        self.weight = weight
        # 输出老虎的体重
        # print(f'老虎的初始体重为:{self.weight}')

    # 判断用实例方法、类方法、静态方法的哪一种?如果方法要使用实例属性,则必然是实例方法
    # 实例方法:喂食
    def feed(self, food):
        # 判断
        if food == 'meat':
            print("喂对了!动物的体重加10斤!!此时{self.name}的体重为{self.weight}斤!")
            # 访问实例属性
            self.weight += 10
        else:
            print("喂错了!动物的体重减10斤!!此时{self.name}的体重为{self.weight}斤!")
            self.weight -= 10

    # 实例方法:叫声
    def roar(self):
        print("wow!wow!wow!")
        # 每叫一次,动物的体重减5斤
        self.weight -= 5

    # # 静态方法:跳跃
    # @staticmethod
    # def jump():
    #     print(f'{Tiger.name}会跳跃')
    #
    # # 类方法
    # @classmethod
    # def a(cls):
    #     # 在类方法中访问静态属性有 两种方法:1、类名.静态属性名 2、cls.静态属性名(cls指的就是这个类)
    #     print("这里是类方法!")


# 定义羊类
class Sheep():
    # 静态属性
    name = "羊"

    # 实例属性
    def __init__(self, weight):
        self.weight = weight
        # print(f"此时{self.name}的体重为{self.weight}")

    # 实例方法:喂食
    def feed(self, food):
        if food == "grass":
            self.weight += 10
            print(f"喂对了,体重加10斤!此时{self.name}的体重为{self.weight}斤!")
        else:
            self.weight -= 10
            print(f"喂错了,体重减10斤!此时{self.name}的体重为{self.weight}斤!")

    # 实例方法:嚎叫
    def roar(self):
        print("mie!mie!mie!")
        # 每嚎叫一次,体重减5斤
        self.weight -= 5


# 定义房间类
class Room():
    def __init__(self, num, animal):
        # 房间号
        self.num = num
        # 房间中的动物
        self.animal = animal


# 定义一个列表,用来存放生成的10个Room对象
rooms = []

# 生成10个Room对象
# r为 1-10 十个房间号
for i in range(1, 11):
    flag = random.randint(0, 1)
    if flag == 0:
        a = Tiger(200)
    else:
        a = Sheep(100)
        # 实例化Room对象,添加进房间列表
    rooms.append(Room(i, a))

# 创建线程入口函数
def get_time():
    while True:
        end_time = time.time()
        if end_time - start_time > 5:
            print("游戏即将结束!!!")
            # 输出游戏结束时房间内的动物信息
            for r in rooms:
                print(f"第{r.num}号房间的动物是{r.animal.name},目前体重是{r.animal.weight}")
            break
    # 如果时间到了,需要自动结束该模块文件(.py)的执行,无需再继续执行后续的主线程内容
    # 0 表示正常退出模块文件
    os._exit(0)

# 获取游戏开始时间
print("游戏即将开始。。。")
start_time = time.time()

# 创建子线程
th1 = Thread(target=get_time)
# 启动子线程
th1.start()

while True:
    # 随机弹出一个房间
    r1 = random.choice(rooms)
    print(f'本次弹出的是{r1.num}号房间')
    # 选择是否要敲门
    f = input('请选择是否敲门:输入y:')
    if f == 'y':
        # 调用敲门的实例方法
        r1.animal.roar()
    # 不需要敲门,则可以直接喂食
    food = input("请输入投喂的食物:meat or grass?")
    r1.animal.feed(food)

代码执行结果:

游戏即将开始。。。
本次弹出的是10号房间
请选择是否敲门:输入y:游戏即将结束!!!
第1号房间的动物是羊,目前体重是1002号房间的动物是羊,目前体重是1003号房间的动物是羊,目前体重是1004号房间的动物是老虎,目前体重是2005号房间的动物是老虎,目前体重是2006号房间的动物是羊,目前体重是1007号房间的动物是羊,目前体重是1008号房间的动物是羊,目前体重是1009号房间的动物是羊,目前体重是10010号房间的动物是羊,目前体重是100

Process finished with exit code 0

七、生成器

通过列表生成式(列表推导式)
,我们可以创建一个列表,但是,受到内存限制,列表容量肯定是受限的。而且创建一个包含上百万个元素的列表,不仅占用很大的存储空间,如果我们只需要访问前面几个元素,那么后面绝大多数元素占用的空间都白白浪费了。所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的内存空间。在Python中,这种一边循环一边计算的机制,称之为生成器(generator)

7.1 列表推导式

首先,来看一下什么是列表推导式吧?

# 正常生成list
print("************采用循环的方式创建列表***************")
# 创建一个空列表,用来存放元素
list1 = []
for i in range(1, 11):
    list1.append(i)
# 打印列表内容
print(list1)

print("************采用列表推导式的方式创建列表***************")
list2 = [i for i in range(10, 21) if i > 14]
print(type(list2))
print(list2)

代码执行结果:

************采用循环的方式创建列表***************
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
************采用列表推导式的方式创建列表***************
<class 'list'>
[15, 16, 17, 18, 19, 20]

Process finished with exit code 0

7.2 生成器的创建与取值

与列表推导式类似,为了节省内存空间,我们也可以采用生成器的方式,只不过是将 [] 换成 ()

【方式一】创建生成器+取值 :

# 创建生成器
# 方式一:

g1 = (i for i in range(10, 21) if i > 16)
# 打印生成器的数据类型: generator
print(type(g1))
# 直接打印生成器本身,得到打印结果:<generator object <genexpr> at 0x000001613EC86D60>
# 生成器是无法直接输出的,直接输出的是该生成器对象在内存中的地址
print(g1)

# 取值
# 方式一:
print(g1.__next__()) # 17
print(g1.__next__()) # 18
print(g1.__next__()) # 19
print(g1.__next__()) # 20
# print(g1.__next__())  # 报错:StopIteration  超过范围,生成器无法再生成值

代码执行结果:

<class 'generator'>
<generator object <genexpr> at 0x000001E9AD906D60>
17
18
19
20

【方式二】创建生成器+取值 :

def f1():
    n = 4
    while True:
        n += 1
        # yield 是返回值+停止 的作用
        yield n

# 取值
g2 = f1()
# 打印g2的数据类型
print(type(g2))
# 直接打印g2
print(g2)
print(next(g2))  # 5
print(next(g2))  # 6
print(next(g2))  # 7
print(next(g2))  # 8

代码执行结果:

<class 'generator'>
<generator object f1 at 0x00000289FDFBFDD0>
5
6
7
8

Process finished with exit code 0

八、 迭代器

8.1 什么是迭代器?

  • 迭代是访问集合元素的一种方式。迭代器是一个可以记住遍历位置的对象。
  • 迭代器对象从集合的第一个元素开始访问,知道所有的元素被访问结束。
  • 迭代器只能往前,不能后退。
  • 可以被next()函数调用并不断返回下一个值的对象成为迭代器:Iterator

8.2 常见的可迭代对象

  • 生成器
  • 列表、元组、字典、字符串

那么,怎么判断是否可迭代呢?

# 怎么判断一个对象是否可迭代
from collections.abc import Iterable

# 判断列表是可迭代
list1 = [1, 2, 3, 4, 5, 6, 7, 8]
# 如果是可迭代,则返回的是True,否则是False
a = isinstance(list1, Iterable)
print(f'判断列表是否可迭代:{a}')

# 判断整型为不可迭代
b = isinstance(4399, Iterable)
print(f'判断整型是否可迭代:{b}')

代码执行结果:

判断列表是否可迭代:True
判断整型是否可迭代:False

Process finished with exit code 0
  • 需要注意的是,可迭代对象不一定是迭代器,比如 列表、元组、字典、字符串等,虽然是一个可迭代对象,但不是一个迭代器,因为它们不可以使用 next() 方式取值。

  • 虽然可迭代对象列表、元组、字典、字符串等本身不是迭代器,但是可以转换为迭代器。

8.3 将可迭代的对象转换为迭代器

# 怎么判断一个对象是否可迭代
from collections.abc import Iterable

# 判断列表是可迭代
list1 = [1, 2, 3, 4, 5, 6, 7, 8]
# 如果是可迭代,则返回的是True,否则是False
a = isinstance(list1, Iterable)
print(f'判断列表是否可迭代:{a}')
# 列表、字典、元组、字符串等,虽然是可迭代的对象,但不是迭代器,用 next() 取值会报错
# print(next(list1))       # TypeError: 'list' object is not an iterator

# 将可迭代的对象转换为迭代器
b = iter(list1)
print(next(b))
print(next(b))
print(next(b))
print(next(b))
print(next(b))

代码输出结果:

判断列表是否可迭代:True
1
2
3
4
5

Process finished with exit code 0
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值