PYTHON自动化Day10-经典类和新式类的区别、重写父类方法、多线程、多进程、日志模块(封装好的日志类),数据驱动框架的编写

一.重写父类方法、经典类和新式类在python2中的区别:


#两种情况:
#1.父类的方法子类中完全不需要,子类重新写
#2.父类有这个方法,但功能不够完善,子类想要在父类这个方法的基础上再添加一些新功能
class ZLL():
    def smile(self):
        print('哈哈哈')

class Xz(ZLL):  #继承这个父类
    def smile(self):  #重写父类的方法
     #如果想要在子类中执行父类的smile方法
# ZLL().smile() #调用父类 ,注意ZLL后面有(),因为调用的是实例方法,要实例化后才能调用 super(Xz,self).smile() #python2中没有super方法,super方法自动帮我们找到父类,和上面一行方法相同, 注意要写子类的类名,还要写一个self ,如果有多个父类,按顺序找到第一个smile()执行 print('hehe') x=Xz() x.smile()
class My: #经典类 pass class My2(object): #新式类 pass #在python3中没有区别, 都是广度优先 #在python2中,一个深度优先,一个是广度优先 # 经典类深度优先, 新式类是广度优先, 例子:一个类有两个父类,在这个子类中调用一个本身和父类都没有的方法,如果是经典类,在第一个父类没有找到方法的时候,继续找第一个父类的父类中的这个方法,而如果是新式类,在第一个父类没有找到方法的时候,会从第二个父类中找

二.多线程:

import threading,time

# def run():
#     time.sleep(3)
#     print('哈哈哈')
# for i in range(5):   #没有使用多线程,顺序执行需要15秒,串行的
#     run()
#
# for i in range(5):   #使用多线程,只需要3秒,并行的
#     t=threading.Thread(target=run)  #实例化一个线程
#     t.start()

urls = {
    'besttest':'http://www.besttest.cn',
    'niuniu':'http://www.nnzhp.cn',
    'dsx':'http://www.imdsx.cn',
    'cc':'http://www.cc-na.cn',
}

import requests
data={}
def down_html(file_name,url):
    start=time.time()
    res=requests.get(url).content
    open(file_name + '.html','wb').write(res)   #因为没有赋给其他变量,所以不需要关闭
    end=time.time()
    data[url]=end-start
    # print(k,"下载时间是:",end-start)    #如果想把它作为返回值返回的话,多线程是没法返回值的,只能在函数外面定义list或者字典来保存结果

# #1.串行
# start_time=time.time()
# for k,v in urls.items():
#     down_html(k,v)
# end_time=time.time()
# run_time=end_time-start_time
# print("下载总共用时:",run_time)

#2.并行
start_time=time.time()
threads=[]
for k,v in urls.items():
    t=threading.Thread(target=down_html,args=(k,v))  #多线程调用函数传参数要用args
    t.start()
    threads.append(t)
for t in threads:
    t.join()
end_time=time.time()
run_time=end_time-start_time  #在没有加join处理前,这样统计的时间是不准确的,只是统计了主线程启动5个子线程的时间
for k,v in data.items():
    print(k,v)
print("下载总共用时:",run_time)

线程锁:

import threading,time
num=1

# def run():
#     time.sleep(1)        #如果不加这一行,就是num=51,加上了就是num=1,因为run还没有执行到num+=1,主线程就把所有的线程启动完了,继续执行print(num)了
#     global num
#     num+=1
#
# for i in range(50):
#     t=threading.Thread(target=run)
#     t.start()
#
# print(num)

# #例子2
# def run():
#     time.sleep(1)
#     global num
#     num+=1
# ts=[]
# for i in range(50):
#     t=threading.Thread(target=run)
#     t.start()
#     ts.append(t)
# [t.join() for t in ts]            #加入join,num=51,因为主线程等所有子线程结束才结束
#
# print(num)

lock=threading.Lock()  #申请一把锁
def run():
    time.sleep(1)
    global num
    lock.acquire()  #加锁    #加锁解锁来锁定一个数据,是为了避免并行操作数据造成数据异常    python3用不到,会自动帮我们加
    num+=1
    lock.release()  #解锁
ts=[]
for i in range(50):
    t=threading.Thread(target=run)
    t.start()
    ts.append(t)
[t.join() for t in ts]            #加入join,num=51,因为主线程等所有子线程结束才结束

print(num)
 

多线程等待:

import threading,time

def run():
    time.sleep(3)
    print('哈哈哈')

start_time= time.time()
threads=[]
for i in range(5):
    t=threading.Thread(target=run)      #这里如果加了括号就变成了串行, run()
    t.start()
    threads.append(t)
    # t.join() #主线程等待子线程执行结束, 但是如果加在这里就变成串行了,因为主线程要等每一个启动的子线程执行结束再启动下一个子线程

for t in threads:
    print(type(t))
    t.join()  #循环等待,等五个子线程都完成之后再往下进行
end_time=time.time()

print('run_time..',end_time-start_time)

守护线程:

import threading,time

def run():
    time.sleep(3)
    print('哈哈哈')

for i in range(50):
    t=threading.Thread(target=run)
    t.setDaemon(True) #把子线程设置成为守护线程    如果没有这句话,会完整执行完run,print哈哈哈,加上这句,主线程启动完所有子线程就print done,然后就结束了
    t.start()

print('done,运行完成。')

# time.sleep(3)   #加上这句后,不加守护线程也可以打印了,因为主进程不会立即结束,而是等了3秒,3秒后,子线程都执行完成了

三.多进程:

import multiprocessing,threading

def my():
    print('哈哈哈')

def run(num):
    for i in range(num):
        t=threading.Thread(target=my)
        t.start()

if __name__ == '__main__':
    for i in range(5):
        p=multiprocessing.Process(target=run,args=(6,))  #启动1个进程  args里如果只有一个参数比如在后面加一个逗号,这样会启动5个进程,每个进程启动6个线程
        p.start()

四. 日志模块:

import logging

# logging.basicConfig(level=logging.DEBUG,#控制台打印的日志级别,debug会打印debug级别以及所有高于debug级别的log,也就是所有log
#                     filename='my.log',
#                     filemode='a',      # w 清空以前的日志,重新写入,a 在文件里追加
#                     format='%(asctime)s - %(pathname)s[line:%(lineno)d] - %(levelname)s: %(message)s'   #日志格式,固定写法
#                     )
# logging.debug('debug级别,最低级别,一般开发人员用来打印一些调试信息')
# logging.info('info级别,正常输出信息,一般用来打印一些正常的操作')
# logging.warning('waring级别,一般用来打印警信息')
# logging.error('error级别,一般用来打印一些错误信息')
#【注意】上面的代码加上文件名之后,log写入了my.log文件中,但是控制台没有显示log,我们想要控制台也输出,如下


import logging
from logging import handlers
#1.办公室
#2.负责往控制台里输出日志的
#3.往日志文件里面写日志的,按天生成日志,清理日志

logger=logging.getLogger()  #先实例化一个logger对象,先创建一个办公室
logger.setLevel(logging.DEBUG)  #设置日志级别

cl=logging.StreamHandler()  #负责往控制台输出的

#普通的写入log文件的方法,不能分割log文件,不能清理log文件:
# fl = logging.FileHandler(filename='a.log',filemode='a',encoding='utf-8')
#按时间生成日志文件
bl=handlers.TimedRotatingFileHandler(filename='a.log',when='S',interval=3,backupCount=5,encoding='utf-8')     #要特别导入一下,按天生成日志,清理日志  when 指定单位:时分秒等 interval=1 几个单位生成一个,backupCount最多保留几个

fmt=logging.Formatter('%(asctime)s - %(pathname)s[line:%(lineno)d] - %(levelname)s: %(message)s') #指定日志的格式
# when 按什么单位
    #S 秒
    #M
    #H
    #D
    #W interval=0时代表每周一

cl.setFormatter(fmt)  #设置控制台输出的日志格式
bl.setFormatter(fmt)  #设置文件里面写入的日志格式

logger.addHandler(cl)  #把两个分工明确的人加入办公室
logger.addHandler(bl)

logger.debug("我是debug..")
logger.warning("我是waring..")

五.封装好的日志类

import logging
from logging import handlers
class MyLogger():
    def __init__(self,file_name,level='info',backCount=5,when='D'):
        logger = logging.getLogger()  # 先实例化一个logger对象,先创建一个办公室
        logger.setLevel(self.get_level(level))  # 设置日志级别

        cl = logging.StreamHandler()  # 负责往控制台输出的

        bl = handlers.TimedRotatingFileHandler(filename=file_name, when='D',interval=1,backupCount=5,encoding='utf-8')
        fmt = logging.Formatter('%(asctime)s - %(pathname)s[line:%(lineno)d] - %(levelname)s: %(message)s')  # 指定日志的格式
        cl.setFormatter(fmt)  # 设置控制台输出的日志格式
        bl.setFormatter(fmt)  # 设置文件里面写入的日志格式
        logger.addHandler(cl)  # 把两个分工明确的人加入办公室
        logger.addHandler(bl)
        self.logger=logger  #最后再self,这样好写一点
    def get_level(self,str):
        level={
            'debug':logging.DEBUG,
            'info':logging.INFO,
            'warn':logging.WARNING,
            'error':logging.ERROR,
        }
        str=str.lower()
        return level.get(str)

lw_log=MyLogger('lw.log')
lw_log.logger.warning('hahah')
lw_log.logger.debug('debug')

六. 第一个测试框架(数据驱动)

笔记:

1、面向对象
class Test():
country = 'China'
#实例方法
def my(self):
print(self.country)

a = Test()
print(a.country)
a.my()
a.country = 'Jap'
print(a.country)
print(Test.country)
1、总共会print几次
2、每次print都是什么


1、面向对象
重写父类的方法
经典类和新式类的区别:
1、 #pthon2里面,多继承的时候
#经典类是深度优先,
# 新式类是广度优先
#python3里面都是广度优先
2、python2 经典类里面不能用super
python3里面经典类和新式类没有任何的区别。
2、多线程、多进程
1、线程是程序里面最小的执行单元。
2、进程是资源的集合。
线程是包含在一个进程里面的, 一个进程可以有多个线程。
一个进程里面默认有一个线程。

主线程
默认有个主线程
子线程:
主线程启动子线程

1、如果这个函数里面有返回值的话,怎么获取呢?
子线程运行的函数,如果里面有返回值的话,是不能获取到的
只能在外面定义一个list或者字典来存每次处理的结果。
电脑CPU有几核,那么只能同时运行几个线程。
但是呢,python的多线程,只能利用一个CPU的核心。
GIL 全局解释器锁。
2、锁呢就是,在多个线程同时修改一个数据的时候,可能会把数据覆盖,在python2里面需要加锁。
python3里面不加锁也无所谓,默认会自动帮你加锁。
3、守护线程。
只要主线结束,那么子线程立即结束,不管子线程有没有运行完成。

多进程
多用于处理CPU密集型任务
多线程
多用于IO密集型任务
Input Ouput

自动化
框架工具的集合。
1、获取用例
2、调用接口
3、校验结果的
4、发送测试报告
5、异常处理
6、日志

数据驱动
根据数据来去测试的。
代码驱动
测试用例都是写代码来测试的。
关键字驱动
ui自动化
点击 --> .click()
下一步
提交 --> .submit()
{
'点击':click()
'提交':submit()
}

作业1、自己查一下
为什么python的多线程不能利用多核CPU,但是咱们在写代码的时候,多线程的确是在并发,而且还比单线程快。

http://www.nnzhp.cn/archives/590
#Jenkins,安装好