概念与用法详解,装饰器全解

本章结构:

装饰器本质上是3个函数,该函数用来拍卖其余函数,它能够让别的函数在不需求修改代码的前提下扩充额外的效率,装饰器的再次来到值也是一个函数对象。它时时用来有切面必要的景况,比方:插入日志、品质测试、事务管理、缓存、权限校验等采纳场景。装饰器是消除那类难点的绝佳设计,有了装饰器,大家就足以抽离出大量与函数成效本人非亲非故的1律代码并承接起用。总结的讲,装饰器的效果正是为早已存在的对象增加额外的效用。

本文实例讲述了Python装饰器(decorator)定义与用法。分享给大家供大家参考,具体如下:

目录

  • 函数补充进阶
    • 函数对象
    • 函数的嵌套
    • 名称空间与成效域
    • 闭包函数
  • 函数之装饰器
  • 函数之可迭代对象
  • 函数之迭代器
  • 函数之生成器
  • 面向进度的次第设计观念

一.通晓装饰器的前提筹算

严峻来说,装饰器只是语法糖,装饰器是可调用的目的,能够像正常的可调用对象那样调用,特殊的地方是装饰器的参数是1个函数

怎么是装饰器(decorator)

1、函数进阶之函数对象

二.装饰器:无参/带参的被点缀函数,无参/带参的装修函数

近来有1个新的要求,希望可以记录下函数的执行时间,于是在代码中增多日志代码:

简单的说的话,能够把装饰器精晓为三个包装函数的函数,它一般将盛传的函数或许是类做肯定的拍卖,重临修改之后的对象.所以,咱们可以在不修改原函数的底子上,在实行原函数前后推行别的代码.相比较常用的气象有日记插入,事务管理等.

壹. 函数对象

  秉承着漫天皆对象的理念,我们再一次回头来看函数(function)。函数也是二个目的,具备属性(能够利用dir()查询)。作为目的,它还是能赋值给给一个变量、能够看做成分增多到聚焦对象中、可视作参数值传递给任何函数,还是能够当做函数的重回值,那个特点正是率先类对象所特有的。

  • 函数身为贰个目的,具备对象模型的几个通用属性:id、类型、和值。

澳门葡京备用网址 1澳门葡京备用网址 2

#!/usr/bin/env python
#-*- coding:utf-8 -*-

def foo():
    print('from foo')

print(id(foo))      # id属性
print(type(foo))    # 类型
func=foo            # 将函数名赋值给一个变量
print(foo)          # 输出函数的内存地址
print(func)         # func变量指向foo函数的内存地址
func()              # 加()调用执行

# 结果
'''
7266512
<class 'function'>
<function foo at 0x00000000006EE0D0>
<function foo at 0x00000000006EE0D0>
from foo
'''

函数对象

  • 函数能够被引用

澳门葡京备用网址 3澳门葡京备用网址 4

#!/usr/bin/env python
# -*- coding:utf-8 -*-
def foo():
    print('from foo')

foo()
func=foo    #引用,赋值
print(foo)
print(func)
func()
#结果
'''
from foo
<function foo at 0x10eed8f28>
<function foo at 0x10eed8f28>
from foo
'''

函数的引用

  • 可以当做参数字传送递,即赋值给变量或作为实参传递

澳门葡京备用网址 5澳门葡京备用网址 6

def foo():
    print('from foo')

def bar(func):      # 参数func为foo
    print(func)     # func参数的内存地址
    func()          # 加()调用func

bar(foo)            # 将foo函数对象作为参数传递给bar函数并调用
#结果
'''
<function foo at 0x00000000007EE0D0>
from foo
'''

函数的引用

  • 函数能够是重回值

澳门葡京备用网址 7澳门葡京备用网址 8

def foo():
    print('from foo')

def bar(func):      # 参数func为foo函数名
    return func     # 返回foo函数的内存地址

f=bar(foo)          # 调用bar函数并将返回的foo函数内存地址赋值给f变量
print(f)            # 输出对应的foo内存地址
f()                 # 加()即调用,此处相当于调用foo函数,即f()=foo()
# 结果
'''
<function foo at 0x0000000000D4E0D0>
from foo
'''

函数作为再次回到值

  • 能够视作容器类型的因素

  注:
函数对应能够存放在容器成分(元组、列表、字典)和变量中

澳门葡京备用网址 9澳门葡京备用网址 10

def foo():
    print('from foo')

dic = {'func':foo}      # 将foo函数对象作为value放入字典中

foo()                   # 调用foo函数
print(dic['func'])      # 字典dic的key值func对应的value为foo函数的内存对象,即foo函数对象作为容器中的一个元素存放
dic['func']()           # 内存地址加()便可以调用,即dic['func]()=foo()
#结果
'''
from foo
<function foo at 0x00000000006EE0D0>
from foo
'''

函数作为容器的成分

  • 应用

澳门葡京备用网址 11澳门葡京备用网址 12

# def select(sql):
#     print('----〉select:%s' % sql)
#
# def insert(sql):
#     print('----〉insert:%s' % sql)
#
# def update(sql):
#     print('----〉update:%s' % sql)
#
# def delect(sql):
#     print('----〉delect:%s' % sql)
#
# sql_dic = {
#     'select':select,
#     'delect':delect,
#     'insert':insert,
#     'update':update
# }
# def main():
#     while True:
#         sql = input('sql>>>').strip()
#         if not sql:continue
#         sql_l = sql.split(' ')
#         if sql_l[0] in sql_dic:
#             sql_dic[sql_l[0]](sql_l)
#
# main()
'''
结果:
sql>>>select * form fafafa
----〉select:['select', '*', 'form', 'fafafa']
sql>>>insert * faormafa  faf a
----〉insert:['insert', '*', 'faormafa', '', 'faf', 'a']
sql>>>
'''

应用

三.装饰器的老毛病

import time
#遵守开放封闭原则
def foo():
    start = time.time()
    # print(start)  # 1504698634.0291758从1970年1月1号到现在的秒数,那年Unix诞生
    time.sleep(3)
    end = time.time()
    print('spend %s'%(end - start))
foo()

装饰器

二. 函数嵌套

  • 函数的嵌套定义

概念:
所谓嵌套,并不像别的语言中的在二个函数中调用另2个函数,而是在概念一个函数的时候,函数体里仍是可以够定义另三个函数。

干什么?因为函数是用def语句定义的,凡是其他语句能够出现的地点,def语句同样能够出现。
像这么定义在别的函数内的函数叫做内部函数,内部函数所在的函数叫做外部函数。当然,我们能够多层嵌套,那样的话,除了最外层和最内层的函数之外,其余函数既是外表函数又是内部函数。

特色:
内函数能够访问外函数的功能域。

澳门葡京备用网址 13澳门葡京备用网址 14

def f1():      # def 关键字 函数f1
    def f2():  # 函数f2
        print('from f2')
        def f3():   # 函数f3
            print('from f3')
        f3()        # 调用f3
    f2()            # 调用

f1()    # 调用f1函数

# 结果
'''
from f2
from f3
'''

View Code

  • 函数的嵌套调用

澳门葡京备用网址 15澳门葡京备用网址 16

# 判断两个数字的大小,返回最大值
def max2(x,y):
    return x if x > y else y

# 判断4个数字的大小
def max4(a,b,c,d):
    res1=max2(a,b)  # 调用msx2函数
    res2=max2(res1,c)
    res3=max2(res2,d)
    return res3

print(max4(10,99,31,22))
 # 结果
 '''
 99
 '''

函数的嵌套调用 

四.python叁的嵌入装饰器

bar()、bar2()也有接近的急需,怎么办?再在bar函数里调用时间函数?那样就变成大气同1的代码,为了减弱重复写代码,我们得以这么做,重新定义3个函数:专门设按期期:

最简易的函数,重临八个数的和

三. 命名空间与功效域

共二种名称空间:

  • 嵌入名称空间  

  • 全局名称空间

  • 局地名称空间

a. 内置名称空间: 随着python解释器的开发银行而发生

 当使用内建立模型块中等高校函授数或别的功用时,能够直接行使,不用加多内建模块的名字;然而,固然想要向内建立模型块中增多一些效益,以便在此外函数中都能一贯行使而不
用再开始展览import,那时,将在导入内建模块,在内建立模型块的命名空间(即__dict__字典属性)中加多该作用。

澳门葡京备用网址 17澳门葡京备用网址 18

print(sum)
print(max)
print(min)

# built-in
'''
<built-in function sum>
<built-in function max>
<built-in function min>
'''
# 在Python2.X版本中,内建模块被命名为__builtin__,而到了Python3.X版本中,却更名为builtins。
import builtins
for i in dir(builtins):
    print(i)

停放名称空间

b.
全局名称空间:文件的试行会生出全局名称空间,指的是文本等第定义的名字都会放入该空间 

澳门葡京备用网址 19澳门葡京备用网址 20

x=1         # 全局
def func(): # 全局
    money=2000
    x=2     # 局部
    print('from func')

print(x)
print(func)
func()
print(x)
print(money)    # 输出失败:NameError: name 'money' is not defined   未定义

# 结果
'''
1
<function func at 0x0000000000A5E1E0>
from func
1
'''

大局名称空间

c. 局地名称空间:调用函数时会发生部分名称空间,只在函数调用时一时半刻绑定,调用截止解绑定

澳门葡京备用网址 21澳门葡京备用网址 22

x=10000     # 全局
def func():
    x=1     # 局部,调用结束后即刻销毁
    def f1():
        pass

一对名称空间

5.本文参考

import time
def show_time(func):
    start_time=time.time()
    func()
    end_time=time.time()
    print('spend %s'%(end_time-start_time))


def foo():
    print('hello foo')
    time.sleep(3)

show_time(foo)
def calc_add(a, b):
 return a + b
calc_add(1, 2)

4. 作用域

命名空间的可知性便是效率域

  • 大局效率域:内置名称空间,全局名称空间
  •  局地功能域:局地名称空间

代码中名字的寻觅顺序:局地名称空间—>全局名层空间—>内置名称空间

a. 查看全局效率域内的函数:gloabls()

b. 查看局地功能域内的函数:locals()

生命周期

a.
全局效用域的名字:全局有效,在其余岗位都能被访问到,除非del删掉,不然会直接并存到文件进行实现

b.
局地功能域的名字:局地有效,只可以在部分范围调用,只在函数调用时才有效,调用甘休就失效

澳门葡京备用网址 23澳门葡京备用网址 24

x=1000
x=1000
def func():
    x=2

print(globals())    # 查看全局作用域内的名字:gloabls()
print(locals())     # 查看全局作用域内的名字:gloabls(),此处由于在文件级别查看,所以globals() is locals()=True
print(globals() is locals())
'''
{'__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000000000685B70>, '__package__': None, '__doc__': None, '__name__': '__main__', 'func': <function func at 0x0000000000B5E1E0>, '__spec__': None, '__cached__': None, 'x': 1000, '__file__': 'E:/YQLFC/study/day04/day4/名称空间与作用域.py', '__builtins__': <module 'builtins' (built-in)>}
{'__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000000000685B70>, '__package__': None, '__doc__': None, '__name__': '__main__', 'func': <function func at 0x0000000000B5E1E0>, '__spec__': None, '__cached__': None, 'x': 1000, '__file__': 'E:/YQLFC/study/day04/day4/名称空间与作用域.py', '__builtins__': <module 'builtins' (built-in)>}
True
'''

示例1

澳门葡京备用网址 25澳门葡京备用网址 26

x=1000
def func(y):
    x=2
    print(locals())     # 查看全局作用域内的名字
    print(globals())    # 查看全局作用域内的名字
    print(globals() is locals())

func(1)

#结果
'''
{'y': 1, 'x': 2}
{'__name__': '__main__', '__builtins__': <module 'builtins' (built-in)>, 'func': <function func at 0x0000000000A5E1E0>, '__doc__': None, '__file__': 'E:/YQLFC/study/day04/day4/名称空间与作用域.py', '__cached__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000000009F5B70>, 'x': 1000, '__spec__': None}
False
'''

示例2

 

然而那样的话,你基础平台的函数修改了名字,轻易被业务线的人投诉的,因为大家每一回都要将四个函数作为参数字传送递给show_time函数。而且那种艺术已经毁损了本来面目标代码逻辑结构,从前实行工作逻辑时,实行运转foo(),不过未来不得不改成show_time(foo)。那么有没有更加好的法门的吧?当然有,答案正是装饰器。

不过未来又有新的急需,计算求和操作耗费时间,很简短,求和前获得一下岁月,求和后再拿走贰次,求差就能够

5. 闭包函数

闭包函数必须满意以下三个原则:

  • 概念在其间函数
  • 带有对表面功效域而非全局成效域的引用,该内部函数就称为闭包函数

 一句话来说:
在函数A的函数体中定义了函数B,且函数B引用了函数A中的变量,并且调用函数A重回函数B的函数对象,那么此时函数B就是闭包函数。

澳门葡京备用网址 27澳门葡京备用网址 28

# 定义实例,对象隐藏,全局不可见
# def f1():
#     # x内部隐藏,全局不可见
#     x = 1
#     def f2():
#         print(x)
#
#     return f2    # 返回函数f2对象
#
# f=f1()
# # print(f)
# # x因为隐藏,所以全局作用域无效
# x=100000000
# f()
'''
结果:
1
'''

闭包示例

闭包应用: 惰性总结

澳门葡京备用网址 29澳门葡京备用网址 30

#闭包应用:惰性计算
from urllib.request import urlopen

def index(url):
    def get():
        return urlopen(url).read()  # 此处引用了外层作用域url变量

    return get      # 返回函数对象

oldboy=index('http://crm.oldboyedu.com')    # 调用index函数

print(oldboy().decode('utf-8'))         # 加()即调用

# 闭包函数相对与普通函数会多出一个__closure__的属性,里面定义了一个元组用于存放所有的cell对象,
# 每个cell对象一一保存了这个闭包中所有的外部变量
print(oldboy.__closure__[0].cell_contents)
#结果
'''
http://crm.oldboyedu.com
'''

x=1
# y=2
def f1():
    # x=1
    y=2
    def f2():
        print(x,y)      # 此处引用外部变量y
    return f2

f=f1()
print(f.__closure__[0].cell_contents)
# 结果
'''
2
'''

应用

掌握装饰器的前提:1.颇具东西都以目的(函数能够视作对象传递) 二.闭包

def show_time(f):
    def inner():
        start = time.time()
        f()
        end = time.time()
        print('spend %s'%(end - start))
    return inner

@show_time #foo=show_time(f)
def foo():
    print('foo...')
    time.sleep(1)
foo()

def bar():
    print('bar...')
    time.sleep(2)
bar()
import datetime
def calc_add(a, b):
 start_time = datetime.datetime.now()
 result = a + b
 end_tiem = datetime.datetime.now()
 print "result:", result, "used:", (end_tiem - start_time).microseconds, "μs"
 return result
calc_add(1, 2)

 

闭包的定义:
一)函数嵌套
二)内部函数使用外部函数的变量
三)外部函数的重返值为在那之中等学校函授数

输出结果:

现在呢,函数calc_diff(a, b),总结a-b,也想总结减法操作的年华差,很好办,把那段代码复制过去.然则要是大家未来想编的是1个数学函数库,种种函数都想计算其执行耗费时间,总不可能多少个1个复制代码,想个越来越好的办法.

二、函数之装饰器(Decorators)

上面写一个极端轻松的闭包的例证:

foo...
spend 1.0005607604980469
bar...

小编们领略,在Python中等高校函授数也是被视为对象的,能够看成参数字传送递,那么壹旦把计算耗费时间的独自为3个单独的函数calc_spend_time(),然后把要求总括耗费时间的函数举例calc_add的引用传递给它,在calc_spend_time中调用calc_概念与用法详解,装饰器全解。add,这样有着的须要总结耗费时间的函数都不要修改本人的代码了.

1. 定义

器即函数

装饰即修饰,意指为别的函数加多新职能

装饰器定义:本质便是函数,成效是为别的函数增添新成效

装饰器本人能够是任何可调用对象,棉被服装饰的靶子也足以是专断可调用对象

1 def test(name):
2     def test_in():
3         print(name)
4     return test_in
5 
6 func = test('whyz')
7 func()

函数show_time正是装饰器,它把真正的事务方法f包裹在函数里面,看起来像foo被上下时间函数装饰了。在这一个事例中,函数进入和剥离时
,被号称1个横切面(Aspect),那种编程情势被称呼面向切面的编程(Aspect-Oriented
Programming)。

def calc_spend_time(func, *args, **kargs):
 start_time = datetime.datetime.now()
 result = func(*args, **kargs)
 end_tiem = datetime.datetime.now()
 print "result:", result, "used:", (end_tiem - start_time).microseconds, "μs"
def calc_add(a, b):
 return a + b
calc_spend_time(calc_add, 1, 1)
# calc_spend_time(calc_add, a=1, b=2)

贰. 装饰器要求依照的标准

1.不改动被点缀函数的源代码(开放封闭原则)

二.为棉被服装饰函数加多新效用后,不改造被修饰函数的调用格局

装饰器的原型:

@符号是装饰器的语法糖,在概念函数的时候利用,防止再1遍赋值操作

看起来也不错,担当总括的函数不用更换,只需调用的时候作为参数字传送给计算时间差的函数.但正是那,调用的时候情势变了,不再是clac(一, 二),而是calc_spend_time(clac_add, 1,
2),万一calc_add大规模被调用,那么还得壹处一处找,然后修改回复,依然很麻烦.假使想不改造代码,就得使clac()calc_spend_time(clac)效益同样,那么能够在calc_spend_time()里把传播的clac包装一下,然后回到包装后的新的函数,再把重回的包裹好的函数赋给clac,那么calc()的功力就和上例calc_spend_time(calc())成效同样.

三. 装饰器的得以实现

装饰器的机能是将被点缀的函数当作参数字传送递给与装饰器对应的函数(名称同样的函数),并回到包装后的被点缀的函数”

一贯看暗示图,当中 a 为与装饰器 @a 对应的函数, b
为装饰器修饰的函数,装饰器@a的效率是:

澳门葡京备用网址 31

一言以蔽之:@a 就是将 b 传递给
a(),并赶回新的 b = a(b)

装饰器(decorator)是干嘛的?对于倍受封装的原函数来讲,装饰器能够在丰富函数实行前大概实行后分别运营一些代码,使得能够再装饰器里面访问并修改原函数的参数以及重回值,以得以完成约束定义、调节和测试程序、注册函数等目的。装饰器一般再次回到3个包装器(wrapper),而functools.wraps正是装饰包装器的装饰器。

 1 import time
 2 def showtime(func):
 3     def wrapper():
 4         start_time = time.time()
 5         func()
 6         end_time = time.time()
 7         print('spend is {}'.format(end_time - start_time))
 8 
 9     return wrapper
10 
11 def foo():
12     print('foo..')
13     time.sleep(3)
14 
15 foo = showtime(foo)
16 foo()

装饰器在Python使用那样方便都要归因于Python的函数能像普通的对象同样能当做参数字传送递给此外函数,能够被赋值给其它变量,能够用作重临值,能够被定义在其余三个函数内。

import datetime
def calc_spend_time(func):
 def new_func(a, b):
  start_time = datetime.datetime.now()
  result = func(a, b)
  end_tiem = datetime.datetime.now()
  print "result:", result, "used:", (end_tiem - start_time).microseconds, "μs"
 return new_func
def calc_add(a, b):
 return a + b
calc_add = calc_spend_time(calc_add)
calc_add(1, 2)

壹. 装饰器的主导落到实处

澳门葡京备用网址 32澳门葡京备用网址 33

import time

def timmer(func):       # 传入一个函数对象,有且只有一个参数
    def wrapper():    # 接收多个值
        start_time=time.time()      # 开始时间
        res=func()    # 此处func()=index()
        stop_time=time.time()       # 结束时间
        print('run time is %s' %(stop_time-start_time))
    return wrapper                  # 返回函数对象

@timmer  # 将装饰器的语法糖,在需要装饰的函数正上方,形如@func   index=timmer(index)
def index():
    time.sleep(3)
    print('welcome to index')

index()
# 结果
'''
welcome to index
run time is 3.0
'''

装饰器的大旨写法

不带参数的装饰器:(装饰器,被点缀函数都不带参数)

装饰器有2个特征,1是足以把被装饰的函数替换来别的函数, 贰是足以在加载模块时候立刻施行

语法糖

二. 装修多少个函数且棉被服装饰函数有参数

澳门葡京备用网址 34澳门葡京备用网址 35

'''
2、多实例添加,及传参数函数
'''
import time
def timmer(func):
    # 传递参数,保证通用性,应为可变长参数(*args,**kwargs),可接受所有类型的实参
    def wrapper(*args,**kwargs):
        start_time=time.time()
        # 传递参数,保证通用性,应为可变长参数(*args,**kwargs),可接受所有类型的实参
        # 有返回值,存值
        res=func(*args,**kwargs)
        stop_time=time.time()
        print('run time is %s' %(stop_time-start_time))
        # 有返回值,返回
        return res
    return wrapper

@timmer     #index=timmer(index)
def index():
    time.sleep(3)
    print('welcome to index')
    # 有返回值,定义
    return 1

#再次调用只需要加@timmer
@timmer
def foo(name):
    time.sleep(1)
    print('from foo')

# 有返回值,传值打印
res=index() #wrapper()
print(res)

res1=foo('shuke')  #res1=wrapper('egon')
print(res1)
'''
运行结果:
welcome to index
run time is 3.000380039215088
1
from foo
run time is 1.0001308917999268
None
'''

装点多个函数及函数指点参数

 1 import time
 2 def showtime(func):
 3     def wrapper():
 4         start_time = time.time()
 5         func()
 6         end_time = time.time()
 7         print('spend is {}'.format(end_time - start_time))
 8 
 9     return wrapper
10 
11 @showtime  #foo = showtime(foo)
12 def foo():
13     print('foo..')
14     time.sleep(3)
15 
16 @showtime #doo = showtime(doo)
17 def doo():
18     print('doo..')
19     time.sleep(2)
20 
21 foo()
22 doo()
def decorate(func):
    print('running decorate', func)
    def decorate_inner():
        print('running decorate_inner function')
        return func()
    return decorate_inner

@decorate
def func_1():
    print('running func_1')

if __name__ == '__main__':
    print(func_1)
    #running decorate <function func_1 at 0x000001904743DEA0>
    # <function decorate.<locals>.decorate_inner at 0x000001904743DF28>
    func_1()
    #running decorate_inner function
    # running func_1

上边的例证正是装饰器的概念,包装函数的函数.事实上下面的事例还是能更加精简

三. 效仿用户登录,一遍登入,数次应用

澳门葡京备用网址 36澳门葡京备用网址 37

# 定义一个字典用于维护用户登陆状态
login_user={'user':None,'status':False}

def auth(func):
    def wrapper(*args,**kwargs):                            # 接收多个参数值
        if login_user['user'] and login_user['status']:     # 字典key对应的value有值,直接调用
            res=func(*args,**kwargs)
            return res
        else:
            name=input('>>: ')
            password=input('>>: ')
            if name == 'shuke' and password == '123':       # 用户登陆成功,修改字典中的用户登陆状态
                login_user['user']='shuke'
                login_user['status']=True
                print('\033[45mlogin successful\033[0m')
                res=func(*args,**kwargs)
                return res
            else:
                print('\033[45mlogin err\033[0m')
    return wrapper

@auth
def index():
    print('welcome to index page')
@auth
def home(name):
    print('Hello %s,welcome to home page' %name)
index()
home('shuke')

#结果
'''
login successful
welcome to index page
Hello shuke,welcome to home page
'''

装饰器的应用

带参数的被点缀的函数

通过args
和 *kwargs 传递被修饰函数中的参数

import datetime
def calc_spend_time(func):
 def new_func(a, b):
  start_time = datetime.datetime.now()
  result = func(a, b)
  end_tiem = datetime.datetime.now()
  print "result:", result, "used:", (end_tiem - start_time).microseconds, "μs"
 return new_func
@calc_spend_time
def calc_add(a, b):
 return a + b
calc_add(1, 2)

四. 多装饰器,顺序实践

澳门葡京备用网址 38澳门葡京备用网址 39

import time
def timmer(func):
    def wrapper(*args,**kwargs):
        print('timmer--->wrapper')
        start_time=time.time()
        res=func(*args,**kwargs)
        stop_time=time.time()
        print('run time is %s' %(stop_time-start_time))
        return res
    return wrapper

login_user={'user':None,'status':False}
def auth(func):
    def wrapper(*args,**kwargs):
        print('auth--->wrapper')
        if login_user['user'] and login_user['status']:
            res=func(*args,**kwargs)
            return res
        else:
            name=input('name: ')
            password=input('pwd: ')
            if name == 'shuke' and password == '123':
                login_user['user']='shuke'
                login_user['status']=True
                print('\033[45mlogin successful\033[0m')
                res=func(*args,**kwargs)
                return res
            else:
                print('\033[45mlogin err\033[0m')
    return wrapper

# 顺序执行
@auth       # timmer = auth--->wrapper--->timmer
@timmer     # index = auth--->wrapper--->timmer--->wrapper(index)
def index():
    time.sleep(2)
    print('welcome to index page')

# 顺序执行,调转则timmer包含auth增加了程序执行时间
@timmer  # auth = timmer--->wrapper--->auth
@auth  # home = timmer--->wrapper--->auth---->wrapper(home)
def home(name):
    time.sleep(2)
    print('Hello %s, welcome to home page' %name)
index()
home('shuke')
'''
结果:
auth--->wrapper
name: shuke
pwd: 123
login successful
timmer--->wrapper
welcome to index page
run time is 2.0
timmer--->wrapper
auth--->wrapper
Hello shuke, welcome to home page
run time is 2.0
'''

三个装饰器,自上而下实践

 1 import time
 2 def showtime(func):
 3     def wrapper(a, b):
 4         start_time = time.time()
 5         func(a,b)
 6         end_time = time.time()
 7         print('spend is {}'.format(end_time - start_time))
 8 
 9     return wrapper
10 
11 @showtime #add = showtime(add)
12 def add(a, b):
13     print(a+b)
14     time.sleep(1)
15 
16 @showtime #sub = showtime(sub)
17 def sub(a,b):
18     print(a-b)
19     time.sleep(1)
20 
21 add(5,4)
22 sub(3,2)

 

@calc_spend_time正是语法糖,它的真面目便是:calc_add = calc_spend_time(calc_add)

5. 带参数的装饰器

澳门葡京备用网址 40澳门葡京备用网址 41

import time
def timmer(func):
    def wrapper(*args,**kwargs):
        print('====>timmer.wrapper')
        start_time=time.time()
        res=func(*args,**kwargs) #auth_wrapper
        stop_time=time.time()
        print('run time is %s' %(stop_time-start_time))
        return res
    return wrapper



login_user={'user':None,'status':False}
def auth(driver='file'):
    def auth2(func):
        def wrapper(*args,**kwargs):
            print('=======>auth.wrapper')
            time.sleep(5)
            if driver == 'file':
                if login_user['user'] and login_user['status']:
                    res=func(*args,**kwargs)
                    return res
                else:
                    name=input('>>: ')
                    password=input('>>: ')
                    if name == 'shuke' and password == '123':
                        login_user['user']='shuke'
                        login_user['status']=True
                        print('\033[45mlogin successful\033[0m')
                        res=func(*args,**kwargs)
                        return res
                    else:
                        print('\033[45mlogin err\033[0m')
            elif driver == 'ldap':
                print('==========ldap的认证')
            elif driver == 'mysql':
                print('==========mysql的认证')
                return func(*args,**kwargs)
            else:
                print('=========未知的认证来源')
        return wrapper
    return auth2


# 顺序执行,index函数的装饰器参数为file,走mysql部分的认证逻辑
@auth('file')   #@auth2====>index=auth2(index)===>index=auth_wrapper
@timmer         #index=timmer(auth_wrapper) #index=timmer_wrapper
def index():
    time.sleep(3)
    print('welcome to index page')

# home函数的装饰器参数为mysql,走mysql部分的认证逻辑
@auth(driver='mysql')
def home(name):
    print('Hello %s, welcome to home page' %name)
index()         #timmer_wrapper()
home('shuke')   #wrapper('shuke')

'''
# 结果
=======>auth.wrapper
>>: shuke
>>: 123
login successful
====>timmer.wrapper
welcome to index page
run time is 3.0
=======>auth.wrapper
==========mysql的认证
Hello shuke, welcome to home page
'''

有参装饰器

带参数的装饰器(装饰函数),

def decorate(func):
    def decorate_inner(*args, **kwargs):
        print(type(args), type(kwargs))
        print('args', args, 'kwargs', kwargs)
        return func(*args, **kwargs)
    return decorate_inner

@decorate
def func_1(*args, **kwargs):
    print(args, kwargs)

if __name__ == '__main__':
    func_1('1', '2', '3', para_1='1', para_2='2', para_3='3')

#返回结果
#<class 'tuple'> <class 'dict'>
# args ('1', '2', '3') kwargs {'para_1': '1', 'para_2': '2', 'para_3': '3'}
# ('1', '2', '3') {'para_1': '1', 'para_2': '2', 'para_3': '3'}

无参数的函数装饰器

陆. python functools.wraps装饰器模块

先来看2个不应用functools.wraps的装饰器例子。

澳门葡京备用网址 42澳门葡京备用网址 43

def tracer(func):
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        print('%s(%r,%r)->%r'%(func.__name__,args,kwargs,result))
        return result
    return wrapper

@tracer
def fibonacci(n):
    if n in (0,1):
        return n
    return (fibonacci(n-1)+fibonacci(n-2))


fibonacci(3)
print(fibonacci)
print('help:')
help(fibonacci)

'''
# 结果
fibonacci((1,),{})->1
fibonacci((0,),{})->0
fibonacci((2,),{})->1
fibonacci((1,),{})->1
fibonacci((3,),{})->2
<function tracer.<locals>.wrapper at 0x00000000007DE840>
help:
Help on function wrapper in module __main__:

wrapper(*args, **kwargs)
'''

未使用functools.wraps

澳门葡京备用网址 ,能够见到,装饰器完全能够平常干活。。。

只是,函数的名字成为装饰器中的包装器了!!!help内置函数也失效了

也正是说,原函数的品质失效了

假设想要保留原函数的质量,就足以用到functools.wraps了

澳门葡京备用网址 44澳门葡京备用网址 45

from functools import wraps
def tracer(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        print('%s(%r,%r)->%r'%(func.__name__,args,kwargs,result))
        return result
    return wrapper

@tracer
def fibonacci(n):
    if n in (0,1):
        return n
    return (fibonacci(n-1)+fibonacci(n-2))


fibonacci(3)
print(fibonacci)
print('help:')
help(fibonacci)

'''
# 结果
fibonacci((1,),{})->1
fibonacci((0,),{})->0
fibonacci((2,),{})->1
fibonacci((1,),{})->1
fibonacci((3,),{})->2
<function fibonacci at 0x0000000000A2E9D8>
help:
Help on function fibonacci in module __main__:

fibonacci(n)
'''

使用functools.wraps

 

事实上是对原来装饰器的1个函数的包装,并回到1个装饰器(3个含有参数的闭包函数),
当使用@time_logger(3)调用的时候,Python能窥见那壹层封装,并将参数字传送递到装饰器的条件去

 

import datetime
def calc_spend_time(func):
 def new_func(*args, **kargs):
  start_time = datetime.datetime.now()
  result = func(*args, **kargs)
  end_tiem = datetime.datetime.now()
  print "result:", result, "used:", (end_tiem - start_time).microseconds, "μs"
 return new_func
@calc_spend_time
def calc_add(a, b):
 return a + b
@calc_spend_time
def calc_diff(a, b):
 return a - b
calc_add(a=1, b=2)
calc_diff(1, 2)

3、可迭代对象

 1 import time
 2 def time_logger(flag = 0):
 3     def showtime(func):
 4         def wrapper(a, b):
 5             start_time = time.time()
 6             func(a,b)
 7             end_time = time.time()
 8             print('spend is {}'.format(end_time - start_time))
 9             
10             if flag:
11                 print('将此操作保留至日志')
12 
13         return wrapper
14 
15     return showtime
16 
17 @time_logger(2)  #得到闭包函数showtime,add = showtime(add)
18 def add(a, b):
19     print(a+b)
20     time.sleep(1)
21 
22 add(3,4)

 

注:

一.迭代的定义

上3次输出的结果为下叁遍输入的初步值,重复的长河称为迭代,每趟重复即二遍迭代,并且每便迭代的结果是下一遍迭代的上马值 

注: 循环不是迭代

while True: #只满足重复,因而不是迭代
    print('====>')

列表、元组、字符串都是可迭代对象

类装饰器:诚如仰仗类内部的__call__方法

 

*args:把富有的参数按现身顺序打包成list
**kargs:把装有的key=value情势的参数打包成3个dict

贰.可迭代的对象

注:
内置__iter__格局的,都以可迭代的靶子。

[1,2].__iter__()
'hello'.__iter__()
(1,2).__iter__()
{'a':1,'b':2}.__iter__()
{1,2,3}.__iter__()
总结: 列表、字符串、元组、字典、集合等都是可迭代对象

 

 1 import time
 2 class Foo(object):
 3     def __init__(self, func):
 4         self._func = func
 5 
 6     def __call__(self):
 7         start_time = time.time()
 8         self._func()
 9         end_time = time.time()
10         print('spend is {}'.format(end_time - start_time))
11 
12 @Foo  #bar = Foo(bar)
13 def bar():
14     print('bar..')
15     time.sleep(2)
16 
17 bar()

带参数的棉被服装饰函数 

带参数的函数装饰器

四、迭代器

动用装饰器的缺点:

import time
# 定长
def show_time(f):
    def inner(x,y):
        start = time.time()
        f(x,y)
        end = time.time()
        print('spend %s'%(end - start))
    return inner

@show_time
def add(a,b):
    print(a+b)
    time.sleep(1)

add(1,2)

只要大家必要理解函数的有的外加消息,举个例子函数小编,能够因而给装饰器函数增添参数来完毕.

1. 为啥要有迭代器?

对于尚未索引的数据类型,必须提供一种不信赖索引取值的迭代格局

# 索引取值,有序
[1,2].__iter__()
'hello'.__iter__()
(1,2).__iter__()
# 无序的
{'a':1,'b':2}.__iter__()
{1,2,3}.__iter__()

1.职位不当的代码->不要在装饰器之外加多逻辑成效
2.不可能装饰@staticmethod 或许 @classmethod已经装修过的主意
3.装饰器会对原函数的元音信举办退换,比方函数的docstring,__name__,参数列表:

不定长

import datetime
def calc_spend_time(author):
 def first_deco(func):
  def new_func(*args, **kargs):
   start_time = datetime.datetime.now()
   result = func(*args, **kargs)
   end_tiem = datetime.datetime.now()
   print author, "result:", result, "used:", (end_tiem - start_time).microseconds, "μs"
  return new_func
 return first_deco
@calc_spend_time('author_1')
def calc_add(a, b):
 return a + b
@calc_spend_time('author_2')
def calc_diff(a, b):
 return a - b
calc_add(a=1, b=2)
calc_diff(1, 2)

2. 迭代对象与迭代器之间的关系

 如下图所示:

澳门葡京备用网址 46

这里x是1个列表,为可迭代对象,使用iter()方法后,此时,得到一个迭代器,迭代器内部装有三个情形,该情状用于记录当前迭代所在的任务,以方便下次迭代的时候取得科学的因素。

迭代器有一种具体的迭代器类型,比方list_iteratorset_iterator。可迭代对象完毕了__iter__措施,该办法再次来到2个迭代器对象,能够动用next()方法依次获得迭代器里面包车型客车成分,

当迭代器成分全体被拿走后,此时下次迭代会获得二个StopIteration错误。

上面对装饰器第第多个缺陷实行剖析,

import time
#不定长
def show_time(f):
    def inner(*x,**y):
        start = time.time()
        f(*x,**y)
        end = time.time()
        print('spend %s'%(end - start))
    return inner

@show_time
def add(*a,**b):
    sum=0
    for i in a:
        sum+=i
    print(sum)
    time.sleep(1)

add(1,2,3,4)

Python内置装饰器

三. 迭代器定义

迭代器:可迭代对象进行__iter__主意,得到的结果就是迭代器,迭代器对象有__next__方法

它是一个带状态的靶子,他能在您调用next()主意的时候回来容器中的下多个值,任何达成了__iter____next__()模式的靶子都以迭代器,__iter__再次回到迭代器自个儿,__next__回来容器中的下贰个值,借使容器中并没有愈多因素了,则抛出StopIteration卓殊。

迭代器的达成

澳门葡京备用网址 47澳门葡京备用网址 48

i={'a':1,'b':2,'c':3}.__iter__()

print(i.__next__())
print(i.__next__())
print(i.__next__())
print(i.__next__())
'''
a
b
c
Traceback (most recent call last):
  File "E:/YQLFC/study/day04/day4/迭代器.py", line 64, in <module>
    print(i.__next__())
StopIteration
'''

迭代器的兑现

历次调用next()方法的时候做两件事: 

  1. 为下三次调用next()艺术修改意况
  2. 为当前本次调用生成再次来到结果

迭代器如同叁个懒加载的工厂,等到有人供给的时候才给它生成值再次来到,没调用的时候就处于休眠状态等待下3遍调用,对于拍卖大数据量的列表、元组、文件等足以很好的节约内部存款和储蓄器的利用。

 1 import time
 2 def showtime(func):
 3     def wrapper():
 4         start_time = time.time()
 5         func()
 6         end_time = time.time()
 7         print('spend is {}'.format(end_time - start_time))
 8 
 9     return wrapper
10 
11 @showtime  #foo = showtime(foo)
12 def foo():
13     print('foo..')
14     time.sleep(3)
15 
16 def doo():
17     print('doo..')
18     time.sleep(2)
19 
20 print(foo.__name__)
21 print(doo.__name__)

带参数的装饰器

Python内置的装饰器有七个:staticmethodclassmethodproperty

4.何以判别贰个对象是可迭代的目的,照旧迭代器对象?

澳门葡京备用网址 49澳门葡京备用网址 50

from collections import Iterable,Iterator

'abc'.__iter__()
().__iter__()
[].__iter__()
{'a':1}.__iter__()
{1,2}.__iter__()

f=open('a.txt','w')
f.__iter__()

# 下列数据类型都是可迭代的对象
print(isinstance('abc',Iterable))
print(isinstance([],Iterable))
print(isinstance((),Iterable))
print(isinstance({'a':1},Iterable))
print(isinstance({1,2},Iterable))
print(isinstance(f,Iterable))

# 只有文件是迭代器对象
print(isinstance('abc',Iterator))
print(isinstance([],Iterator))
print(isinstance((),Iterator))
print(isinstance({'a':1},Iterator))
print(isinstance({1,2},Iterator))
print(isinstance(f,Iterator))
'''
#结果
True
True
True
True
True
True
False
False
False
False
False
True
'''

迭代目的和迭代器数据类型 

常用的数据类型,都是可迭代对象,但是未选拔iter()方法以前,暗许唯有文件是迭代器。

总结:

  • 可迭代对象:唯有__iter__措施,实践该措施得到的迭代器对象
  • 迭代器:有__iter____next__()方法

注:

  • 对于迭代器对象的话,推行__iter__主意,获得的结果依然如故是它本身
  •  python中for循环的贯彻精神上正是经过将有所的目标内部转为迭代器之后展开迭代巡回的,for循环内处了StopIteration相当。
  • for迭代 == while + try…except…(至极管理形式)

结果为:

在地方的装饰器调用中,比方@show_time,该装饰器唯一的参数就是进行专门的事业的函数。装饰器的语法允许大家在调用时,提供其他参数,比方@decorator(a)。那样,就为装饰器的编写和行使提供了更加大的八面驶风。

staticmethod:把类中的方法定义为静态方法,使用staticmethod装饰的秘技能够使用类或许类的实例对象来调用,不必要传入self

 5. 迭代器的优缺点

优点:

  • 提供了1种不依赖下标的迭代方式
  • 就跌迭代器本人来讲,更省去内存

澳门葡京备用网址 51澳门葡京备用网址 52

l=[10000,2,3,4,5]

i=iter(l)

print(i)
print(next(i))
'''
<list_iterator object at 0x00000000006F42E8>
10000
'''

next()方法取值

缺点:

  • 手足无措赢得迭代器对象的长短
  • 比不上类别类型取值灵活,是一回性的,只好将来取值,不能够往前退

澳门葡京备用网址 53澳门葡京备用网址 54

l=[10000,2,3,4,5]

i=iter(l)

print(i)
print(next(i))
'''
<list_iterator object at 0x00000000006F42E8>
10000
'''

如过河的卒,只好升高不可能后退

PS:

澳门葡京备用网址 55澳门葡京备用网址 56

product = ["Mac pro","iphone","iWatch"]
for index,item in enumerate(product,1):
    print(index,item)
'''
1 Mac pro
2 iphone
3 iWatch
'''

枚举函数enumerate(),实际也是迭代器

 

wrapper
doo
import time
def time_logger(flag=0):
    def show_time(func):
        def wrapper(*args, **kwargs):
            start_time = time.time()
            func(*args, **kwargs)
            end_time = time.time()
            print('spend %s' % (end_time - start_time))
            if flag:
                print('将这个操作的时间记录到日志中')
        return wrapper
    return show_time

@time_logger(flag=1)
def add(*args, **kwargs):
    time.sleep(1)
    sum = 0
    for i in args:
        sum += i
    print(sum)
add(1, 2, 5)
class Human(object):
 """docstring for Human"""
 def __init__(self):
  super(Human, self).__init__()
 @staticmethod
 def say(message):
  if not message:
   message = 'hello'
  print 'I say %s' % message
 def speak(self, message):
  self.say(message)
Human.say(None)
human = Human()
human.speak('hi')

伍、函数之生成器

概念: 生成器函数:只要函数体蕴涵yield关键字,该函数便是生成器函数

透过能够观望,装饰器会对原函数的元音讯实行改换,可以运用wraps,实行原函数音信的丰硕

@time_logger(flag=一) 做了两件事:

输出:

壹. 生成器便是迭代器

澳门葡京备用网址 57澳门葡京备用网址 58

def foo():
    print('first')
    yield 1
    print('second')
    yield 2
    print('third')
    yield 3
    print('fourth')
    yield 4
    print('fifth')

g=foo()
for i in g:
    print(i)

生成器yield关键字

澳门葡京备用网址 59澳门葡京备用网址 60

def foo():
    print('first')
    yield 1
    print('second')
    yield 2
    print('third')
    yield 3
    print('fourth')
    yield 4
    print('fifth')

g=foo()         # 此时g就是一个迭代器
print(g)        # g的内存地址
for i in g:
    print(i)
print(next(g))  # 触发迭代器g的执行,进而触发函数的执行
'''
# 结果
<generator object foo at 0x00000000006E1150>
first
1
second
2
third
3
fourth
4
fifth
Traceback (most recent call last):
  File "E:/YQLFC/study/day04/day4/生成器.py", line 38, in <module>
    print(next(g)) #触发迭代器g的执行,进而触发函数的执行
StopIteration
'''

生成器正是迭代器

注解:wraps本人也是三个装饰器,他能把函数的元新闻拷贝到装饰器函数中**使得装饰器函数与原函数有同一的元新闻

    (1)time_logger(一):获得闭包函数show_time,里面保存蒙受变量flag

I say hello
I say hi

贰.生成器的调用

澳门葡京备用网址 61澳门葡京备用网址 62

def counter(n):
    print('start...')
    i=0
    while i < n:
        yield i
        i+=1
    print('end...')


g=counter(3)
print(g)
print(next(g))
print(next(g))
print(next(g))
print(next(g))
'''
# 结果
<generator object counter at 0x0000000000B51150>
start...
0
1
2
end...
Traceback (most recent call last):
  File "E:/YQLFC/study/day04/day4/生成器.py", line 84, in <module>
    print(next(g))
StopIteration
'''

大致调用

总结:
yield的功能:

  1. 一定于为函数封装好__iter__和__next__方法
  2. return只可以回到3遍值,函数就终止了,而yield能回去多次值,每一回回来都会将函数暂停,下3遍next会从上3遍中断的职位继续实践

以下是3个wraps的例证:

    (2)@show_time   :add=show_time(add)

classmethod:把类中的方法定义为类情势,使用classmethod装饰的法子能够使用类大概类的实例对象来调用,并将该class对象隐式的当作第1个参数字传送入

3. yield程序实例(tail -f a.txt | grep ‘python’ 类功用python程序版)

澳门葡京备用网址 63澳门葡京备用网址 64

#tail -f a.txt | grep 'python' 类功能python程序版

# def tail(filepath):
#     '''
#     tail功能
#     :param filepath: 文件路径
#     :return: 相当于return文件最后一行,后等待文件输入
#     '''
#     with open(filepath,encoding='utf-8') as f:
#         '''
#         seek(offset,whence=0)
#         offset:开始的偏移量,也就是代表需要移动偏移的字节数
#         whence:给offset参数一个定义,表示要从哪个位置开始偏移;0代表从文件开头开始算起,
#         1代表从当前位置开始算起,2代表从文件末尾算起。默认为0
#         '''
#         f.seek(0,2)
#         while True:
#             line=f.readline().strip()
#             if line:
#                 yield line
#             else:
#                 time.sleep(0.2)
#
# #相当于return文件最后一行,后继续等待next下次调用
# t=tail('a.txt')
#
# # 测试tail功能是否有效
# # for line in t:
# #     print(line)
#
# def grep(pattern,lines):
#     '''
#     grep 功能实现
#     :param pattern: 校验关键字
#     :param lines: 要校验的行
#     :return: 相当于return符合检验的行,后等待行继续调用输入
#     '''
#     for line in lines:
#         if pattern in line:
#             yield line
#
#
# g=grep('python',tail('a.txt'))    #此处的tail('a.txt')是一个迭代器
# #返回内存地址
# print(g)
#
# #迭代输出
# for i in g:
#     print(i)

类tail -f a.txt | grep
‘python’功能

 1 import time
 2 from functools import wraps
 3 def showtime(func):
 4 
 5     @wraps(func)    
 6     def wrapper():
 7         start_time = time.time()
 8         func()
 9         end_time = time.time()
10         print('spend is {}'.format(end_time - start_time))
11 
12     return wrapper
13 
14 @showtime  #foo = showtime(foo)
15 def foo():
16     print('foo..')
17     time.sleep(3)
18 
19 def doo():
20     print('doo..')
21     time.sleep(2)
22 
23 print(foo.__name__)
24 print(doo.__name__)

上面的time_logger是允许带参数的装饰器。它实际上是对原有装饰器的一个函数封装,并赶回3个装饰器(八个分包参数的闭包函数)。当本人们使用@time_logger(一)调用的时候,Python能够发掘那壹层的包裹,并把参数传递到装饰器的条件中。

class Human(object):
 """docstring for Human"""
 def __init__(self):
  super(Human, self).__init__()
  self.message = '111'
 def say(message):
  if not message:
   message = 'hello'
  print 'I say %s' % message
 @classmethod
 def speak(cls, message):
  if not message:
   message = 'hello'
  cls.say(message)
human = Human()
human.speak('hi')

 四.  协程函数(生成器,yield关键字的另一种用法)

注:

  • 协程函数能够以二个元组的格局send数据
  • 可以在表面得到协程函数的重回值

结果为:

叠放装饰器

输出同上例

四.壹 协程函数的落到实处

协程函数的运作流程如下图所示:

澳门葡京备用网址 65

澳门葡京备用网址 66澳门葡京备用网址 67

#!/usr/bin/env python
#-*- coding:utf-8 -*-

# 协程函数第一次调用时需要进行初始化,next(g)或者g.send(None)方式都可以,建议使用装饰器的方式进行初始化协程函数
def deco(func):
    def wrapper(*args,**kwargs):
        res = func(*args,**kwargs)
        next(res)
        return res
    return wrapper

@deco
def eater(name):
    print('%s reay to eat'%name)
    food_li = []
    while True:
        food = yield food_li            # 此处food_li为函数的返回值,可以在函数外部获取
        food_li.append(food)
        print("%s start to eat %s" %(name,food))

g = eater('shuke')
# next(g) = g.send(None)            # 第一次调用必须先进行初始化,可以使用此种方式进行初始化也可以使用装饰器的方式。
print(g.send('香蕉'))
print(g.send('樱桃'))
res = g.send('西瓜')
print(res)

'''
# 结果
shuke reay to eat
shuke start to eat 香蕉
['香蕉']
shuke start to eat 樱桃
['香蕉', '樱桃']
shuke start to eat 西瓜
['香蕉', '樱桃', '西瓜']
'''

应用yield关键字贯彻协程函数

foo
doo

施行各样是什么

property:把艺术成为属性

四.二 yield关键字的表明式情势

应用: 使用yield表达式方式模仿”grep -rl ‘python’ /root”命令

澳门葡京备用网址 68澳门葡京备用网址 69

#grep -rl 'python' /root

import os

def init(func):
    def wrapper(*args,**kwargs):
        res=func(*args,**kwargs)
        next(res)
        return res
    return wrapper

@init                   # 装饰器:初始化函数
def search(target):
    while True:
        search_path=yield
        g=os.walk(search_path)          # 遍历目录
        for par_dir,_,files in g:       # 用_丢弃子目录
            for file in files:
                file_abs_path=r'%s\%s' %(par_dir,file)      # 拼接文件路径file_abs_path
                # print(file_abs_path)
                target.send(file_abs_path)                  # 遍历文件路径并send给opener函数

@init
def opener(target):
    while True:
        file_abs_path=yield
        # print('opener func==>',file_abs_path)
        with open(file_abs_path,encoding='utf-8') as f:
            target.send((file_abs_path,f))          # send文件路径及文件对象f,以元组的形式send数据

@init
def cat(target):            # target为grep函数对象
    while True:
        file_abs_path,f=yield  #(file_abs_path,f)
        for line in f:
            tag=target.send((file_abs_path,line))       # send文件路径及文件行内容line,以元组的形式send数据
            if tag:
                break
@init
def grep(target,pattern):   # target为printer函数对象,pattern为匹配的字符串'python'
    tag=False
    while True:
        file_abs_path,line=yield tag
        tag=False
        if pattern in line:
            tag=True
            target.send(file_abs_path)

@init
def printer():      # 输出匹配成功的文件路径
    while True:
        file_abs_path=yield
        print(file_abs_path)



x=r'E:\YQLFC\study\day05\day5\a'        # 查找的目录

g=search(opener(cat(grep(printer(),'python'))))
print(g)
g.send(x)

'''
#结果
<generator object search at 0x0000000000D514C0>
E:\YQLFC\study\day05\day5\a\a.txt
E:\YQLFC\study\day05\day5\a\b\b.txt
E:\YQLFC\study\day05\day5\a\b\c\d\d.txt
'''

grep -rl ‘python’ /root

 

常用的放权装饰器:一.staticmethod: 类似实现了静态方法
注入今后,能够直接 : 类名.方法

要是二个函数被多少个装饰器修饰,其实应当是该函数先被最中间的装饰器修饰后(上边例子中等高校函授数main()先被inner装饰,造成新的函数),变成另四个函数后,再一次棉被服装饰器修饰

class Human(object):
 """docstring for Human"""
 def __init__(self, value):
  super(Human, self).__init__()
  self._age = value
 @property
 def age(self):
  return self._age
human = Human(20)
print human.age

陆. 面向进程的次序设计思想

面向过程的顺序设计的风味: 是1种流水生产线式的编制程序思路,是机械式的。

优点:
  • 程序的结构清晰,能够把复杂的难题大概

缺点:
  • 增加性差

利用场景: linux内核,git,httpd…

 

2.**property*:经过property装饰过的函数
不再是三个函数,而是2个property,
恍如完成get,set方法***

def outer(func):
    print('enter outer', func)
    def wrapper():
        print('running outer')
        func()
    return wrapper

def inner(func):
    print('enter inner', func)
    def wrapper():
        print('running inner')
        func()
    return wrapper

@outer
@inner
def main():
    print('running main')

if __name__ == '__main__':
    main()

#返回结果
# enter inner <function main at 0x000001A9F2BCDF28>
# enter outer <function inner.<locals>.wrapper at 0x000001A9F2BD5048>
# running outer
# running inner
# running main

更加多关于Python相关内容可查阅本站专题:《Python数据结构与算法教程》、《Python
Socket编制程序才干计算》、《Python函数使用技艺总计》、《Python字符串操作本事汇总》及《Python入门与进阶非凡教程》

1 @property
2 def width(self):
3 return self.__width
4 
5 @width.setter
6 def width(self, newWidth):
7 self.__width = newWidth

类装饰器

可望本文所述对我们Python程序设计有所支持。

3.classmethod: 与staticmethod很相像,貌似就只有这点分别:
第3个参数需如果代表小编类的 cls 参数,
能够来调用类的习性,类的法门,实例化对象等。

比较函数装饰器,类装饰道具备灵活度大、高内聚、封装性等优点。使用类装饰器还足以依靠类内部的__call__措施,当使用 @ 方式将装饰器附加到函数上时,就会调用此方法。

import time

class Foo(object):
    def __init__(self, func):
        self._func = func

    def __call__(self):
        start_time=time.time()
        self._func()
        end_time=time.time()
        print('spend %s'%(end_time-start_time))

@Foo  #bar=Foo(bar)
def bar():
    print ('bar')
    time.sleep(2)

bar()    #bar=Foo(bar)()>>>>>>>没有嵌套关系了,直接active Foo的 __call__方法

规范库中有各种装饰器

诸如:装饰艺术的函数有property, classmethod,
staticmethod; functools模块中的lru_cache, singledispatch,  wraps 等等

from functools class=”Apple-converted-space”> import class=”Apple-converted-space”> lru_cache

from functools class=”Apple-converted-space”> import class=”Apple-converted-space”> singledispatch

from functools class=”Apple-converted-space”> import class=”Apple-converted-space”> wraps

 

您或者感兴趣的稿子:

  • python怎么样定义带参数的装饰器
  • 介绍Python的@property装饰器的用法
  • Python中的各类装饰器详解
  • 深刻了然python中的闭包和装饰器
  • Python装饰器的函数式编制程序详解
  • 详解Python中的装饰器、闭包和functools的教程
  • 巧用Python装饰器
    免去调用父类构造函数的分神
  • Python中的多种装饰器
  • python重试装饰器示例
  • 实例批注Python编制程序中@property装饰器的用法
  • Python自定义装饰器原理与用法实例分析

 

functools.wraps使用装饰器十分大地复用了代码,不过他有1个毛病正是原函数的元消息不见了,比方函数的docstring、__name__、参数列表,先看例子:

def foo():
    print("hello foo")
print(foo.__name__)# foo

def logged(func):
    def wrapper(*args, **kwargs):
        print (func.__name__ + " was called")
        return func(*args, **kwargs)
    return wrapper

@logged
def cal(x):
    resul=x + x * x
    print(resul)

cal(2)
#6
#cal was called
print(cal.__name__)# wrapper
print(cal.__doc__)#None
#函数f被wrapper取代了,当然它的docstring,__name__就是变成了wrapper函数的信息了。

好在我们有functools.wraps,wraps本身也是一个装饰器,它能把原函数的元信息拷贝到装饰器函数中,这使得装饰器函数也有和原函数一样的元信息了。

from functools import wraps

def logged(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print(func.__name__ + " was called")
        return func(*args, **kwargs)
    return wrapper

@logged
def cal(x):
    return x + x * x

print(cal.__name__)  # cal

行使装饰器会发出大家恐怕不指望出现的副效能, 举个例子:改动被修饰函数称谓,对于调节和测试器大概目的连串化器等急需运用内省建制的那多个工具,只怕会不可能常常运作;

事实上调用装饰器后,会将同3个效益域中原来函数同名的可怜变量(比如上边的func_1),重新赋值为装饰器再次回到的对象;使用@wraps后,会把与个中等学校函授数(被修饰函数,比方上面包车型的士func_一)相关的重中之重元数据总体复制到外围函数(举个例子下面包车型客车decorate_inner)

from functools import wraps

def decorate(func):
    print('running decorate', func)
    @wraps(func)
    def decorate_inner():
        print('running decorate_inner function', decorate_inner)
        return func()
    return decorate_inner

@decorate
def func_1():
    print('running func_1', func_1)

if __name__ == '__main__':
    func_1()

#输出结果
#running decorate <function func_1 at 0x0000023E8DBD78C8>
# running decorate_inner function <function func_1 at 0x0000023E8DBD7950>
# running func_1 <function func_1 at 0x0000023E8DBD7950>

 

 

本文参考:

1.

2.

3.

4.

 

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*
*
Website