首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Python——神奇的闭包(装饰器的应用)

Python——神奇的闭包(装饰器的应用)

作者头像
Ed_Frey
发布2019-07-04 14:41:42
4700
发布2019-07-04 14:41:42
举报
文章被收录于专栏:奔跑的键盘侠奔跑的键盘侠
最近没什么时间写新的内容,就把之前学习过程中整理的 内容分享给大家,关于闭包是一个很牛逼的功能,具体应用 原理,可直接参考代码中间的注释。 # !/usr/bin/env python3.6 # -*- coding: utf-8 -*- #__author__: Ed Frey #date: 2018/8/7 # 用途1:当闭包执行完后,仍然能够保持住当前的运行环境。 # 比如说,如果你希望函数的每次执行结果,都是基于这个函数上次的运行结果。我以一个类似棋盘游戏的例子 # 来说明。假设棋盘大小为50*50,左上角为坐标系原点(0,0),我需要一个函数,接收2个参数,分别为方向 # (direction),步长(step),该函数控制棋子的运动。棋子运动的新的坐标除了依赖于方向和步长以外, # 当然还要根据原来所处的坐标点,用闭包就可以保持住这个棋子原来所处的坐标。 ''' origin = [0, 0] # 坐标系统原点 legal_x = [0, 50] # x轴方向的合法坐标 legal_y = [0, 50] # y轴方向的合法坐标 def create(pos=origin): def player(direction,step): # 这里应该首先判断参数direction,step的合法性,比如direction不能斜着走,step不能为负等 # 然后还要对新生成的x,y坐标的合法性进行判断处理,这里主要是想介绍闭包,就不详细写了。 new_x = pos[0] + direction[0]*step new_y = pos[1] + direction[1]*step pos[0] = new_x pos[1] = new_y #注意!此处不能写成 pos = [new_x, new_y],原因在上文有说过 return pos return player player = create() # 创建棋子player,起点为原点 print (player([1,0],10)) # 向x轴正方向移动10步 print (player([0,1],20)) # 向y轴正方向移动20步 print (player([-1,0],10)) # 向x轴负方向移动10步 ''' # 用途2:闭包可以根据外部作用域的局部变量来得到不同的结果,这有点像一种类似配置功能的作用,我们可以 # 修改外部的变量,闭包根据这个变量展现出不同的功能。比如有时我们需要对某些文件的特殊行进行分析,先 # 要提取出这些特殊行。 ''' def make_filter(keep): def the_filter(file_name): file = open(file_name) lines = file.readlines() file.close() filter_doc = [i for i in lines if keep in i] return filter_doc return the_filter # 如果我们需要取得文件"result.txt"中含有"pass"关键字的行,则可以这样使用例子程序 filter = make_filter("pass") filter_result = filter("result.txt") '''
# import time
#
#
# def show_time(func):
#     def wrapper():
#         start_time = time.time()
#         func()
#         end_time = time.time()
#         print('spend %s' % (end_time - start_time))
#
#     return wrapper
#
#
# @show_time  # 此句相当于foo=show_time(foo)
# def foo():
#     print('hello foo')
#     time.sleep(3)
#
#
# @show_time  # 此句相当于bar=show_time(bar)
# def bar():
#     print('in the bar')
#     time.sleep(2)
#
#
# foo()
# print('***********')
# bar()

#上所示,这样我们就可以省去bar = show_time(bar)这一句了,直接调用bar()即可得到想要的结果。如果我们有其他的类似函数,我们可以继续调用装饰器来修饰函数,而不用重复修改函数或者增加新的封装。这样,我们就提高了程序的可重复利用性,并增加了程序的可读性。

#      这里需要注意的问题:  foo=show_time(foo)其实是把wrapper引用的对象引用给了foo,而wrapper里的变量func之所以可以用,就是因为wrapper是一个闭包函数。


# 带参数的被装饰函数
'''
import time


def show_time(func):
    def wrapper(a, b):
        start_time = time.time()
        func(a, b)
        end_time = time.time()
        print('spend %s' % (end_time - start_time))

    return wrapper

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

add(2, 4)

'''


#***********************************不定长参数
# import time
#
# 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))
#
#     return wrapper
#
# @show_time   #add=show_time(add)
# def add(*args,**kwargs):
#
#     time.sleep(1)
#     sum=0
#     for i in args:
#         sum+=i
#     print(sum)
#
# add(2,4,8,9)

#
# 装饰器还有更大的灵活性,例如带参数的装饰器:在上面的装饰器调用中,比如 @ show_time,该装饰器唯一的参数就是执行业务的函数。装饰器的语法允许我们在调用时,提供其它参数,比如 @ decorator(
#     a)。这样,就为装饰器的编写和使用提供了更大的灵活性。

# 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(3)
# def add(*args, **kwargs):
#     time.sleep(1)
#     sum = 0
#     for i in args:
#         sum += i
#     print(sum)
#
#
# add(2, 7, 5)


# @time_logger(3)

#
# 做了两件事:
# (1)time_logger(3):得到闭包函数show_time,里面保存环境变量flag
# (2)@show_time:add=show_time(add)
#
# 上面的time_logger是允许带参数的装饰器。它实际上是对原有装饰器的一个函数封装,并返回一个装饰器(一个含有参数的闭包函数)。当我
# 们使用 @ time_logger(3)
# 调用的时候,Python能够发现这一层的封装,并把参数传递到装饰器的环境中。



'''
#多层装饰器
def makebold(fn):
    def wrapper():
        return "<b>" + fn() + "</b>"
    return wrapper

def makeitalic(fn):
    def wrapper():
        return "<i>" + fn() + "</i>"
    return wrapper

@makebold
@makeitalic
def hello():
    return "hello alvin"

# hello()
print(hello())
'''

来源: https://www.cnblogs.com/yuanchenqi/articles/5830025.html
题外话:不积跬步,无以至千里,很多看似微小的知识点,如果
能通透的理解,再加以多多的应用练习,然后再多多的总结联想,串联
起各个知识点,很快你也可以变的牛逼起来。  
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-10-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 奔跑的键盘侠 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档