专栏首页奔跑的键盘侠Python——神奇的闭包(装饰器的应用)

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

最近没什么时间写新的内容,就把之前学习过程中整理的 内容分享给大家,关于闭包是一个很牛逼的功能,具体应用 原理,可直接参考代码中间的注释。 # !/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
题外话:不积跬步,无以至千里,很多看似微小的知识点,如果
能通透的理解,再加以多多的应用练习,然后再多多的总结联想,串联
起各个知识点,很快你也可以变的牛逼起来。  

本文分享自微信公众号 - 奔跑的键盘侠(runningkeyboardhero)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-10-12

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Python——关于排序算法(合并排序法)

    如果有2个已经排好序的列表a = [3,5,6,9]和b = [2,4,7,8],以及目标c = []

    Ed_Frey
  • Python——九九乘法表(While循环)

    徘徊了两个月,只好重新来过。看了一下专业培训的,上课大概就要上500小时+,我这短短几个月的酱油式填鸭,连100个小时都没凑?,接下来就简单的习题式的更新些帖子...

    Ed_Frey
  • Python——关于排序算法(插入法)

    接上一篇冒泡排序法,今天来讲一下插入排序法(insertion sorting),接下来几期还会有选择排序法、合并排序法、快速排序法等等,敬请期待哦。

    Ed_Frey
  • 老男孩Python全栈开发(92天全)视频教程 自学笔记16

    玩蛇的胖纸
  • 《手把手教你》系列进阶篇之3-python+ selenium自动化测试 - python几种骚操作你都知道吗?(详细教程)

      这篇文章主要是给小伙伴或者童鞋们介绍和分享 python几种骚操:读取配置文件、获取根目录的相对路径、获取系统时间和格式化时间显示、字符串切割等等操作。为...

    北京-宏哥
  • python基础-装饰器

    我们到了新的阶段了,也是逃不过的一劫,装饰器,有的兄弟们估计听说过,这可是一个神奇的东西,

    晴天Online
  • Python学习笔记六(Python t

    通过python time模块提供的函数和方法可以获取与时间相关的操作,例如:获取系统时间,统计程序执行时间,WEB程序的响应时间等。 1)time.tim...

    用户2398817
  • Python time模块详解(时间戳↔元组形式↔格式化形式三者转化)

    在Python中, time有三种表示形式 1 时间戳:1970年1月1日之后的秒 2 元组格式化形式 包含了:年、日、星期 得到time.stru...

    学到老
  • Python日期字符串比较 转

    需要用python的脚本来快速检测一个文件内的二个时间日期字符串的大小,其实实现很简单,首先一些基础的日期格式化知识如下 复制代码

    双面人
  • curl你花了多长时间?

    curl -w "@curl-format.txt" -o /dev/null -s "http://www.baidu.com/"

    随心助手

扫码关注云+社区

领取腾讯云代金券