接口测试学习-python第八课(面向对象第二课)

一、重写父类的方法

重写包含两种定义,其一是父类的方法不可用了,需要完全重新编写;其二是保留父类方法的同时新增一些功能。

首先是全部重写,很好理解,就是将整个方法都修改掉。比如下面的类Zll中,定义了一个smile方法,笑的方式是“哈哈哈”。而继承Zll的子类Dcg,笑的方式并不是这个,那么他就重写smile方法。

1 class Zll(object):
2     def smile(self):
3         print('哈哈哈')
4 
5 
6 class Dcg(object):
7     def smile(self):
8         print('嘿嘿嘿')

其次是修改父类方法。就是在保留父类方法的基础上进行添加或者部分修改。如果父类只有一个,那么直接在方法中调用父类方法即可。比如:

1 class Lw(object):
2     def smile(self):
3         Zll.smile()
4         print('啊啊啊啊')

但当子类继承了多个父类时,像这样去调用就非常麻烦了,因为还要分辨这个方法属于哪一个父类。这时候可以用super()方法自动查找父类。当有多个父类时,super()会默认从第一个父类开始查找。

1 class Xz(Zll, Dcg, Lw):
2     def smile(self):
3         # Zll().smile()  # 先调用父类的方法,这样可以使用父类的功能
4         super(Xz, self).smile()  # 可以帮助子类自动找到其父类
5         # 如果子类继承自多个父类,super自动从第一个开始寻找smile方法
6         print('呵呵呵呵')  # 重写了父类的方法

二、经典类和新式类

经典类和新式类的区别主要有以下两点:

1、定义时有所不同

1 class A(object):  # 新式类
2     pass
3 
4 
5 class A1():  # 经典类
6     pass

2、多重继承时,查找方法的方式不同

在python2中,经典类的查找方式是深度查找,新式类的查找方式是广度查找。到python3默认所有的类都是新式类,所以都默认为广度查找了。如下面代码中,实例化对象d使用方法smile时,因为其类D继承自C,B,A,都是新式类,所以D也是新式类,其查找smile的方法是广度优先也就是C->B->A的顺序查找的。而d1是D1类的实例化对象,D1继承自C1,B1和A1都是经典类,所以D1也是经典类,d1.smile()时查找方法是深度优先也就是C1->A1->B1。

 1 class A(object):
 2     pass
 3 class A1():
 4     pass
 5 
 6 class B(A):
 7     pass
 8 class B1(A1):
 9     pass
10 
11 class C(A):
12     def smile(self):
13         print('哈哈')
14 class C1(A1)
15     def smile(self):
16         print('haha')
17 
18 class D(C,B,A):
19     pass
20 class D1(C1,B1,A1):
21     pass
22 
23 d = D()
24 d.smile()
25 d1 = D1()
26 d1.smile

三,多线程和多进程

一个进程可以有多个线程,进程是资源的合集,线程是进程中的最小执行单元。用很简单的方式来展示一下串行和并行。并行就是实例化线程,然后一起start开始干活。

 1 import threading
 2 import time
 3 
 4 
 5 def run():
 6     time.sleep(3)  # 做一件事需要三秒
 7     print('哈哈哈')
 8 
 9 for i in range(5):  # 串行,一个人干完另一个人再干活
10     run()
11 
12 for i in range(5):  # 并行
13     t = threading.Thread(target=run)  # 实例化一个线程
14     t.start()

如果我们要比较串行和并行的执行时间,串行的可以直接在程序开始时记录当前时间,结束后记录当前时间,然后相减即可。但是并行不行,因为并行记录的是主线程的时间,其实子线程还在运行中,直接这样记录是不准确的。我们可以用下面的方法,记录每次子线程,然后让主线程等待一下子线程

 1 def run():
 2     time.sleep(3)  # 做一件事需要三秒
 3     print('哈哈哈')
 4 start_time = time.time()
 5 threads = []
 6 for i in range(5):
 7     t = threading.Thread(target=run)
 8     t.start()
 9     threads.append(t)
10     # t.join()  # 这个就是主线程等待子线程执行结束,但是直接这样是不行的因为每次t里面都是不同的线程
11 #     这样就变成了串行了,一个干完等待,继续下一个,然后等待
12 for t in threads:  # 主线程先运行了run()然后就继续往下走了,然后启动了子线程,所以此时主线程就已经在等待中了
13     t.join()  # 这样就是每个线程都等待一下
14 end_time = time.time()
15 run_time = end_time-start_time
16 print('执行总共花了时间%s' % run_time)

四、线程锁

当所有的线程都在修改同一个数据时,可能出现覆盖的情况,比如一个数不断加1,因为后面的结果数覆盖了前面的数据,导致结果不正确。这个时候就要对这个变量加一个线程锁,让它在正在被修改的时候不会被其他任务修改。其实python3是会自动加锁的,但是我们也需要学习一下这个概念和方法,必须使用python2编程时就要用到了。

 1 import threading, time
 2 num = 1
 3 lock = threading.Lock()  # 申请一把锁
 4 
 5 def run():
 6     time.sleep(1)
 7     global num
 8     lock.acquire()  # 加上锁,其实python3是会默认加锁的
 9     num += 1
10     lock.release()  # 解锁
11 ts = []
12 for i in range(50):
13     t = threading.Thread(target=run)
14     t.start()
15     ts.append(t)
16 [t.join() for t in ts]  # 如果不等待,主线程跑太快,上面那个time.sleep()会导致num=1就执行完了
17 print(num)

五、守护线程

只要主线程结束,立刻结束其他子线程。不论子线程是否运行成功。

 1 import threading,time
 2 def run():
 3     time.sleep(3)  # 做一件事需要三秒
 4     print('哈哈哈')
 5 
 6 for i in range(5):
 7     t = threading.Thread(target=run)
 8     t.setDaemon(True)  # 把子线程设置为守护线程
 9     t.start()
10 
11 print('Done,运行完成。')
12 time.sleep(3)  # 等三秒是可以运行下一个子线程的,但是等1秒的话来不及走子线程主线程就结束了

六、多进程

多进程用于处理CPU密集型任务。多线程用于处理IO密集型任务。其实python是无法使用多核的,原因如下:

 

 

 1 import multiprocessing,threading
 2 
 3 def my():
 4     print('哈哈哈')
 5 
 6 
 7 def run(num):
 8     for i in range(num):
 9         t = threading.Thread(target=my)
10         t.start()
11 if __name__ == '__main__':
12     for i in range(5):
13         p = multiprocessing.Process(target=run, args=(6,))  # 启动五个进程,每个进程6个线程
14         # 这样就可以利用CPU的多核
15         p.start()

 

posted on 2018-06-01 16:40  四方城郭  阅读(211)  评论(0编辑  收藏  举报