python-Debug、函数装饰器

  • 2019 年 10 月 31 日
  • 筆記

Debug操作:

程序出问题的时候可以用debug来看一下代码运行轨迹,然后找找问题在哪里

1.先给即将debug的代码打上断点:

 2.打完断点之后右键点击debug:

 3.然后依次点击开始按钮让程序开始一步步运行:

函数的装饰器:

定义:装饰器为其他函数添加附加功能,本质上还是一个函数

原则:①不修改被修饰函数的源代码

      ②不修改被修饰函数的调用方式

有这样一个函数:demo()

先导入时间模块,然后函数执行时先睡两秒,在执行打印

1 import time  2 def demo():  3     time.sleep(2)  4     print("welcome sir")  5 demo()

现在想为demo()函数添加一个统计函数运行时间的功能,但是要遵循开放封闭原则

初步思想:

1 import time  2 def demo():  3     start_time = time.time()  4     time.sleep(2)  5     print("welcome sir")  6     end_time = time.time()  7     print("运行时间%s" %(end_time-start_time))  8 demo()

这样就完美解决了,但是,我们要用可持续发展的眼光来看,假如有十万个代码,我们这样一个一个添加,你不加班谁加班?

这个时候我们可以用函数的思维来解决

进步思想:

 1 import time   2 def demo():   3     time.sleep(2)   4     print("welcome sir")   5 def timmer(func_name):   6     def inner():   7         start_time = time.time()   8         func_name()   9         end_time = time.time()  10         print("运行时间%s" %(end_time-start_time))  11     return inner  12 res = timmer(demo)  13 res()

这样看起来非常Nice,用到了高阶函数,嵌套函数,函数闭包,但是我们违反了开放封闭原则,这个时候把res 改成 demo 就可以了

在这里有一个命令,可以直接略过这个赋值,让代码看起来更美观,执行效率更高

 1 import time   2 def timmer(func_name):   3     def inner():   4         start_time = time.time()   5         func_name()   6         end_time = time.time()   7         print("运行时间%s" %(end_time-start_time))   8     return inner   9 @timmer  10 def demo():  11     time.sleep(2)  12     print("welcome sir")  13 demo()

ok,代码完成,这其实就是一个函数装饰器,我们来解释一下代码运行顺序

为装饰器加上返回值:

 1 import time   2 def timmer(func_name):   3     def inner():   4         start_time = time.time()   5         res = func_name()   6         end_time = time.time()   7         print("运行时间%s" %(end_time-start_time))   8         return res   9     return inner  10 @timmer  11 def demo():  12     time.sleep(2)  13     return '函数demo的返回值'  14 val = demo()  15 print(val)

有参数的装饰器:

 1 import time   2 def timmer(func_name):   3     def inner(*args,**kwargs):   4         start_time = time.time()   5         res = func_name(*args,**kwargs)   6         end_time = time.time()   7         print("运行时间%s" %(end_time-start_time))   8         return res   9     return inner  10 @timmer  11 def demo(name,age):  12     time.sleep(2)  13     return '函数demo的返回值,姓名:%s,年龄:%s' %(name,age)  14 val = demo('zrh',20)  15 print(val)

图示流程:

迭代器: 

可迭代协议:只要包括了”_iter_”方法的数据类型就是可迭代的

1 print([1,2,3].__iter__())  #打印结果:<list_iterator object at 0x000002E7F803DE88>

iterable 形容词 可迭代的

1 from collections import Iterable  #检测一个对象是否可迭代  2 print(isinstance('aaa',Iterable))  3 print(isinstance(123,Iterable))  4 print(isinstance([1,2,3],Iterable))

迭代器协议:迭代器中有 __next__ 和 __iter__方法 

iterator 名词 迭代器,迭代器 就是实现了能从其中一个一个的取出值来

检测参数是不是个迭代器:

1 from collections import Iterator  2 print(isinstance(lst_iterator,Iterator))  3 print(isinstance([1,2,3],Iterator))

在python里,目前学过的所有的可以被for循环的基本数据类型都是可迭代的,而不是迭代器。

迭代器包含可迭代对象

可迭代对象转换为迭代器:

可迭代对象._iter_()  这样就变成可一个迭代器

lise_case = [1,2,3].__iter__()

迭代器存在的意义:

1.能够对python中的基本数据类型进行统一的遍历,不需要关心每一个值分别是什么
2.它可以节省内存 —— 惰性运算

for循环的本质:

1 lst_iterator = [1,2,3].__iter__()  2 while True:  3     try:  4         print(lst_iterator.__next__())  5     except StopIteration:  6         break

只不过for循环之后如果参数是一个可迭代对象,python内部会将可迭代对象转换成迭代器而已。

生成器:

Iterator 迭代器

Gerator 生成器

生成器其实就是迭代器,生成器是用户写出来的

 1 def generator_func():    #生成器函数   2     print(123)   3     yield 'aaa'   4 generate = generator_func()   5 print(generate)   6 print(generate.__next__())   7 # 打印结果:   8 # <generator object generator_func at 0x0000018F3942E8C8>   9 # 123  10 # aaa

带yield关键字的函数就是生成器函数,包含yield语句的函数可以用来创建生成器对象,这样的函数也称为生成器函数。

yield语句与return语句的作用相似,都是用来从函数中返回值,return语句一旦执行会立刻结束函数的运行

而每次执行到yield语句并返回一个值之后会暂停或挂起后面的代码的执行,下次通过生成器对象的__next__()、for循环或其他方式索要数据时恢复执行

生成器具有惰性求值的特点

生成器运行顺序:

生成器问题注意1:

 1 def generator_func():    #生成器函数   2     print(123)   3     yield 'aaa'   4     print(456)   5     yield 'bbb'   6 ret_1 = generator_func().__next__()   7 print(ret_1)   8 ret_2 = generator_func().__next__()   9 print(ret_2)  10 # 输出结果:  11 # 123  12 # aaa  13 # 123  14 # aaa  15 def generator_func():    #生成器函数  16     print(123)  17     yield 'aaa'  18     print(456)  19     yield 'bbb'  20 generate_1 = generator_func()  21 ret_1 = generate_1.__next__()  22 print(ret_1)  23 ret_2 = generate_1.__next__()  24 print(ret_2)  25 # 输出结果:  26 # 123  27 # aaa  28 # 456  29 # bbb

第6行和第8行相当于创建了两个生成器,第20行创建了一个生成器,21行和23行都用的是第20行创建的生成器,所以输出结果不一样

生成器问题注意2:

 for循环完了之后生成器数据就取完了,再继续print数据的话,就会报错,因为没有数据可以读了。

一个函数有两个以上的yield,才算一个必要的生成器,如果只有一个yield,那还不如老老实实的去写return

生成器实例:

需求:写一个实时监控文件输入的内容,并将输入内容返回的函数

1 def tail(filename):  2     f = open(filename,encoding='utf-8')  3     f.seek(0,2)  4     while True:  5         line = f.readline()  6         if not line:continue  7         yield line  8 tail_g = tail('file_1')  9 for line in tail_g:print(line,end='')