Python编程
前言
包括类属性与实例属性,属性的隐藏,私有方法与私有属性,多态,反射与单例模式;异常的抓取,else与finally,常见的异常,raise,loguru日志模块;Pytest框架介绍,Pytest执行测试用例,数据驱动;allure环境搭建,生成allure报告;知识点梳理。
一、面向对象
1、类属性与实例属性
class Human:
name = '人类' # 类属性;类和实例共有的属性
def __init__(self, name2):
self.name2 = name2 # 实例属性
man = Human('天乐')
print(man.name2)
print(man.name)
2、属性的隐藏
class Test1:
def __init__(self):
self.a = 100
@property # 装饰器,声明下面的方法是属性而不是方法
def fun2(self): # 其实是参数
return self.a
ts1 = Test1()
print(ts1.fun2)
3、私有属性与私有方法
(1)、私有属性与私有方法不能从外部被调用,也不能被子类继承
(2)、在属性的前面加上__,就是私有属性
(3)、在方法的前面加上__,就是私有方法
(4)、如果前后都有__,不是私有方法,Python自带的一些方法
class Class_test1:
__str1 = 'ABC' # 私有属性
str2 = 'DEF'
def __method1(self): # 私有方法
print('这是一个私有方法')
# def method2(self):
# print('这是一个普通方法')
def method2(self):
print(self.__str1) # 调用私有属性
self.__method1() # 调用私有方法
cls1 = Class_test1()
# print(cls1.__str1) # 私有属性不能被直接调用
# cls1.__method1 # 私有方法不能被直接调用
# cls1.method2()
cls1.method2()
4、多态
(1)、不同的类中有同名方法,调用方法时,根据对象的不同,实现的操作也不同,称之为多态
(2)、比如,调用狗的叫的方法为狗叫,调用猫的叫的方法为猫叫
# 新建一个狗的类,里面有叫的方法
class Dog:
def say(self):
print('汪汪汪')
# 新建一个猫的类,里面有叫的方法
class Cat:
def say(self):
print('喵喵喵')
dog = Dog()
cat = Cat()
def animal_say(animal):
animal.say()
animal_say(dog)
animal_say(cat)
class Restaurant:
pass
class Gongbaojiding(Restaurant):
def menu(self):
print('宫爆鸡丁')
class Yuxiangrousi(Restaurant):
def menu(self):
print('鱼香肉丝')
class Qingjiaotudousi(Restaurant):
def menu(self):
print('青椒土豆丝')
customer1 = Gongbaojiding() # 顾客1点了宫保鸡丁
customer2 = Yuxiangrousi()
customer3 = Qingjiaotudousi()
def waiter(obj): # 服务员上菜
obj.menu()
waiter(customer1)
waiter(customer2)
waiter(customer3)
5、反射与单例
5.1、反射
(1)、在做程序开发中,我们常常会遇到这样的需求:需要执行对象里的某个方法,或需要调用对象中的某个变量,但是由于种种原因我们无法确定这个方法或变量是否存在,这时我们需要用一个特殊的方法或机制要访问和操作这个未知的方法或变量,这种机制就称之为反射
(2)、Python的反射主要是指三个函数:
1)、hasattr
-
hasattr(对象,属性或方法名)
-
在对象里找有没有属性或方法名,返回值是布尔型
print(hasattr(str, 'replace'))
print(hasattr(list, 'append'))
2)、getattr
-
getattr(对象,属性或方法名,自定义值)
-
在对象里找有没有属性或方法名,如果能找到,返回找到的属性或方法;如果找不到,也可以返回指定的值
print(getattr(str, 'replace'))
print(getattr(str, 'replace1', '没有该属性或方法'))
3)、setattr
-
setattr(对象,属性,属性值)
-
在对象里修改属性值;如果找不到属性,新建属性并赋值
class Class1:
a = 1
setattr(Class1, 'a', 100)
setattr(Class1, 'b', 200)
print(Class1.a, Class1.b)
5.2、单例模式
一般情况下,类可以生成任意个实例;单例模式只生成一个实例
class Single:
# 构造方法
def __new__(cls, *args, **kwargs): # 构造方法,cls表示类本身,*args运行传任意参数,**kwargs运行传任意参数(键值对)
if not hasattr(cls, 'obj'): # 判断类当中有没有实例,如果没有则新建
cls.obj = super().__new__(cls) # 生成实例对象,继承父类object的new方法
return cls.obj
s1 = Single()
s2 = Single()
print(id(s1), id(s2)) # id打印在内存中的编号
二、异常与日志
1、异常的抓取
(1)、运行一段代码时,如果遇到问题无法执行,程序就会抛出异常
(2)、系统自带的异常,普通用户较难理解
(3)、通过try except体系抓取异常,替换为普通用户能理解的报错信息
try:
input1 = input('请输入一个整数:')
print(1 / input1)
except ZeroDivisionError: # except可以写多个
print('0不能作为分母!')
except TypeError:
print('您输入的不是整数!')
except: # 不指定异常类型,则捕获任何异常;抓取顺序从上往下
print('程序出现异常')
2、else与finally
(1)、有时希望程序没有出现异常时执行某些代码,可以加入else语句
(2)、如果程序没有出现异常,则执行一次else中的语句
(3)、如果出现异常,则不执行
try:
input1 = int(input('请输入一个整数: '))
print(1 / input1)
except ZeroDivisionError:
print('0不能作为分母')
except ValueError:
print('您输入的不是整数')
except: # 不指定异常类型,则捕获任何异常
print('程序出现异常')
else: # 程序未出现异常,则执行else中的语句
print('没有出现异常')
(4)、有时希望程序无论是否出现异常都执行某些代码,可以加入finally语句
(5)、无论程序是否出现异常,都会执行finally中的语句
(6)、如果既有else语句也有finally语句,finally写在else的后面
try:
input1 = int(input('请输入一个整数: '))
print(1 / input1)
except ZeroDivisionError:
print('0不能作为分母')
except ValueError:
print('您输入的不是整数')
except: # 不指定异常类型,则捕获任何异常
print('程序出现异常')
else: # 程序未出现异常,则执行else中的语句
print('没有出现异常')
finally:
print('程序运行完毕')
(7)、一个try except语句至少有一个except,可以有多个,也可以有一个else语句和一个finally语句
3、常见的异常
(1)、NameError:变量未定义
print(a)
(2)、IndexError:下标越界
list1 = [100]
print(list1[1])
(3)、FileNotFoundError:找不到文件
with open('D:/12345.txt.txt') as file1:
print(file1.read())
(4)、所有的异常,都是Exception的子类,或者子类的子类
print(NameError.__base__)
print(IndexError.__base__.__base__)
print(LookupError.__base__)
print(FileNotFoundError.__base__)
print(OSError.__base__)
4、raise
有时候,想调试某个代码里的异常,但不知道怎么触发,此时可以使用raise手动抛出异常
try:
raise IOError # 输入输出异常
except IOError:
print('程序出现了IO异常')
5、loguru日志模块
日志的级别 debug(调试级) < info(信息级) < warning(警告级) < error(错误级) < critical(崩溃级)
from loguru import logger
logger.debug('松勤') #打印信息
logger.info('松勤')
logger.warning('松勤')
logger.error('松勤')
logger.critical('松勤')
from loguru import logger
import os
if not os.path.exists('./log'): # 如果当前路径下没有log目录,则新建
os.mkdir('./log') # 新建
logger.remove(handler_id=None) # 不在控制台(pycharm)打印
logger.add('./log/log1.log', rotation='200KB', compression='zip',
encoding='utf-8') # rotation='200KB'文件达到200KB新建个文件;compression='zip'旧文件进行压缩
for i in range(10000):
logger.warning('松勤')
三、pytest入门
测试:预期结果与实际结果是否一致
1、Pytest框架介绍
(1)、Pytest是Python的第三方单元测试框架,比自带的unittest更简洁和高效
(2)、支持315种以上的插件,同时兼容unittest框架
(3)、在unittest框架迁移到pytest框架的时候不需要重写代码
2、Pytest执行测试用例
使用pytest执行测试需要遵循的命名规范
(1)、测试文件必须以test_
开头,或者_test
结尾,pytest所在路径不要用中文或特殊符号
(2)、测试类必须以Test
开头,并且类当中不能有__init__
方法
(3)、测试方法必须以test_
开头
(4)、断言必须使用assert
import pytest
class Test1:
def test_c01(self):
assert 1 == 2 # 比较预期结果与实际结果
if __name__ == '__main__':
pytest.main([__file__]) # __file__ 执行当前文件
import pytest
@pytest.fixture(scope='module') # 装饰器,声明下面的函数是setup函数;setup 在其他函数之前执行; autouse=True 自动使用,当函数不调用fun1时可用
# scope 缺省值 function,每个函数或方法之前都执行一次
# class 每个类之前执行一次
# module 每个模块之前执行一次
# session fixtrue的内容写到conftest.py,目录下的所有文件共用这个配置
# autouse=True 自动调用,不需要作为参数传到函数方法里
def fun1():
print('测试开始')
yield # 声明下面的代码是teardown函数;teardown 在其他函数之后执行
print('测试完成')
class Test1:
def test_some_data(self, fun1):
assert 1 == 2
def test_some_data2(self, fun1):
assert 2 == 3
class Test2:
def test_some_data3(self, fun1):
assert 1 == 2
def test_some_data4(self, fun1):
assert 2 == 3
if __name__ == '__main__':
pytest.main([__file__, '-sv']) # -s 允许打印 -v 显示详细信息
# conftest
import pytest
@pytest.fixture(scope='session', autouse=True) # autouse=True 自动被本目录下文件调用
def fun100():
print('测试开始')
yield
print('测试结束')
if __name__ == '__main__':
pytest.main([__file__, '-sv'])
3、数据驱动
(1)、@pytest.mark.parametrize
(2)、pytest内置装饰器 @pytest.mark.parametrize 可以让测试数据参数化,把测试数据单独管理,类似ddt数据驱动的作用,方便代码和测试数据分离
import pytest
class Test100:
# 'expected_result,actual_result' 是一个参数; [[1, 2], [2, 3], [3 ** 2, 9]] 列表内包含多个子列表
@pytest.mark.parametrize('expected_result,actual_result', [[1, 2], [2, 3], [3 ** 2, 9]])
def test_c100(self, expected_result, actual_result):
assert expected_result == actual_result
if __name__ == '__main__':
pytest.main([__file__])
四、allure报告
1、allure环境搭建
(1)、下载allure.zip
(2)、 解压allure.zip到一个文件目录中,allure需要有jdk环境
(3)、将allure报告安装目录\bin所在的路径添加环境变量path中
(4)、pip install allure-pytest
(5)、验证
2、生成allure报告
import pytest, os
class Test100:
# 'expected_result,actual_result' 是一个参数; [[1, 2], [2, 3], [3 ** 2, 9]] 列表内包含多个子列表
@pytest.mark.parametrize('expected_result,actual_result', [[1, 2], [2, 3], [3 ** 2, 9]])
def test_c100(self, expected_result, actual_result):
assert expected_result == actual_result
if __name__ == '__main__':
pytest.main([__file__, '-s', '--alluredir', './report/report', '--clean-alluredir']) # --clean-alluredir 每次使用前情况
os.system('allure serve ./report/report')
import pytest, os, allure
@allure.epic('项目名称')
@allure.feature('业务模块名称')
class Test9:
@allure.story('接口名称1')
@allure.title('用例标题1')
def test_c08(self):
assert 1 == 2
@allure.story('接口名称2')
@allure.title('用例标题2')
def test_c09(self):
assert 1 == 3
if __name__ == '__main__':
pytest.main([__file__, '-s', '--alluredir', './report/report', '--clean-alluredir']) # --clean-alluredir 每次使用前情况
os.system('allure serve ./report/report')
五、知识点梳理
1、写一个函数,判断字符串是否是回文
def fun1(srcstr: str): # 形参的后面可以加上希望用户输入的数据类型,这个选项没有强制性
if srcstr == srcstr[::-1]:
return True
else:
return False
print(fun1('12321'))
2、写一个函数,可以打印斐波那契数列的前n位
例如:1,1,2,3,5,8,13,21,34,55,89,…
def fun2(n: int):
list2 = []
for i in range(n):
if i < 2:
list2.append(1)
else:
list2.append(list2[-2] + list2[-1])
return list2
print(fun2(10))
3、写一个函数,取列表的基数位
list1 = [100, 200, 300, 400, 500]
list1_new = []
for i in range(len(list1)):
if i % 2 == 0:
list1_new.append(list1[i])
print(list1_new)
4、写一个函数,有一个参数n,返回从1加到n的和
import time
def fun3(n):
start_time = time.time()
sum1 = 0
for i in range(1, n + 1):
sum1 += i
print(f'用时{time.time() - start_time}')
return sum1
print(fun3(100000000))
import time
def fun3_new(n):
start_time = time.time()
sum1 = n * (n + 1) / 2
print(f'用时{time.time() - start_time}')
return sum1
print(fun3_new(100000000))
5、写一个函数,返回n的阶乘,尽量不使用循环
def fun6(n):
if n == 1:
return 1
else:
return n * fun6(n - 1) # 递归
print(fun6(6))
6、写一个倒计时程序
import time # 加载时间模块
for i in range(10, 0, -1):
print(f'\r倒计时{i}秒', end='') # \r 光标回到行首
time.sleep(1) # 程序等待1秒
else:
print('\r倒计时结束')
7、写一个程序,打印九九乘法表
for i in range(1,10): # 控制第二个数值每一行加1
for j in range(1,i+1): # 控制第一个数值在一行一直自增长,直到和第二个数值一样大
print(f'{j}*{i}={i*j}\t',end='')
print()
8、写一个程序,打印100以内质数
list1 = []
for i in range(2, 101):
for j in range(2, i):
if i % j == 0 and i != j:
break
else:
list1.append(i)
print(list1
9、写一个程序,读写excel文件
import xlrd
excel1 = xlrd.open_workbook('D:/松勤VIP接口测试用例-v1.6.xls') # 打开excel文件
sheet1 = excel1.sheets()[1] # 打开下标为1的sheet
list1 = []
number1 = sheet1.nrows # 有效行数
for i in range(1, number1):
list1.append(sheet1.cell_value(i, 6)) # 行,列
# 写入excel
import xlwings as xw
workbook2 = xw.Book('D:/book1.xlsx') # 打开一个excel文件,文件需存在且打开
sheet2 = workbook2.sheets[0] # 打开一个sheet
for i in range(1, len(list1) + 1):
sheet2.range(f'A{i}').value = list1[i - 1]
workbook2.save('D:/book1.xlsx') # 保存