闭包和装饰器

这篇具有很好参考价值的文章主要介绍了闭包和装饰器。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

闭包

在函数内部再定义⼀个函数,并且这个内部函数⽤到了外部的变量,这个函数以及⽤到外部函数的变量及参数叫闭包

def fun_a(num_a):
  # 在函数内部再定义⼀个函数,并且这个内部函数⽤到了外部的变量
  def fun_b(num_b):
    print("in test_in 函数, number_in is %d" % num_b)
    return num_a + num_b
  # 这⾥返回的就是闭包的结果
  return fun_b
# 给fun_a函数赋值,这个10就是给参数num
ret = fun_a(10)
# 注意这⾥的10其实给参数fun_b
print(ret(10))

再比如二次函数:

def line_conf(a, b):
  def line(x):
    return a * x + b
  return line

line1 = line_conf(1, 1)
line2 = line_conf(4, 5)
print(line1(5))         # 结果  6
print(line2(5))         # 结果  25

从这段代码中,函数line与变量a,b构成闭包。在创建闭包的时候,我们通过line_conf的参数a,b说明了这两个变量的取值,这样,我们就确定了函数的最终形式(y = x + 1和y = 4x + 5)。

我们只需要变换参数a,b,就可以获得不同的直线表达函数。

因此,闭包也具有提⾼代码可复⽤性的作⽤。如果没有闭包,我们需要每次创建函
数的时候同时说明a,b,x。

def fun_a():
  fun_list = []
  for i in range(1, 4):
    def fun_b():
      return i * i
    fun_list.append(fun_b)
  return fun_list

f1, f2, f3 = fun_a()
print(f1(), f2(), f3())

这段代码中,我们想得到是1,4,9,可是执行结果却是9,9,9

这是因为,返回的函数引用了变量 i ,但不是立刻执行。等到3个函数都返回时,它们所引用的变量i已经变成了3

最简单的方法就是改为def fun_b(_i=i),这样就每次都把i值传入了

装饰器

装饰器的作用就是为已经存在的对象添加额外的功能

def test1(func):
    def test2():
        print('帮你把饭做好')
        func()
        print('洗碗')
    return test2


@test1    # 相当于eat=test1(eat)
def eat():
    print('我正在吃饭')

执行结果为:
帮你把饭做好
我正在吃饭
洗碗

这样就可以不用做饭洗碗,直接吃饭了

再比如,下面我们用装饰器logger来给所有关于work的函数增加记录日志的功能

from functools import wraps
import time

def logger(func):  # 定义一个记录日志的装饰器
    @wraps(func)
    def write_logging():
        print('[info]--时间是:%s'%time.strftime('%H:%M:%S',time.localtime()))  # 格式化
        func()
    return write_logging

@logger   # 使用装饰器给所有的work增加记录日志的功能
def work():     # 这里使用装饰器的函数不能带参数
    print('我在工作')

结果为:[info]--时间是:16:33:02
            我在工作

@wraps(func)作用是用func函数,即原函数来封装高阶函数,因为work函数调用装饰器后函数名其实是write_logging,加上@wraps(func)后函数名还是func,相当于在原函数基础上增加功能。

上面的装饰器,在work函数中不能传参数,不能知道是谁在哪个时间工作,我们如果想给func函数增加参数,就要在write_logging处增加参数:

def logger(func):  # 定义一个记录日志的装饰器
    @wraps(func)
    def write_logging(*args,**kwargs):   # 可以传多个参数,*args,**kwargs多种参数类型
        print('[info]--时间是:%s'%time.strftime('%H:%M:%S',time.localtime()))  # 格式化
        func(*args,**kwargs)
    return write_logging

@logger
def work_2(name):    
    print('%s 在工作'%name)

work_2('张三')

我们也可以给装饰器本身设置参数,比如我们要把这些数据输入到哪个文件:

def main_logger(log_file='out.log'):     # 不写的话就是默认值
    def logger(func):  # 定义一个记录日志的装饰器
        @wraps(func)
        def write_logging(*args,**kwargs):
            print('[info]--时间是:%s'%time.strftime('%H:%M:%S',time.localtime()))
            with open(log_file,'a') as f:
                f.write('log'+'\n')
            func(*args,**kwargs)
        return write_logging
    return logger

@main_logger('work2.log')   # 再嵌套一层函数,这样就可以传入想写的参数
def work_2(name):
    print('%s 在工作'%name)

work_2('张三')

我们在写代码时如果才想起来调用库函数,可以先写需要的函数,alt加enter快速调用库~

在我们的函数,线程进程等知识点都可以包装成一个类,再由我们自己去手动调用,这样不仅方便,还可以提高代码的可重用性。我们也可以将装饰器封装成一个类:文章来源地址https://www.toymoban.com/news/detail-655911.html

class Logs(object):
    def __init__(self,log_file='out.log',level='info'):
        self.log_file=log_file
        self.level=level

    def __call__(self,func):    # 定义装饰器的,需要有一个接受函数
        @wraps(func)
        def write_logging(*args, **kwargs):
            print('[%s]--时间是:%s' % (self.level,time.strftime('%H:%M:%S', time.localtime())))
            with open(self.log_file, 'a') as f:
                f.write('log' + '\n')
            func(*args, **kwargs)

        return write_logging

@Logs(log_file='work2.log',level='W')   # 在__init__中设置的传入参数
def work_2(name,name2):
    print('%s和%s在工作'%(name,name2))

work_2('张三','李四')

到了这里,关于闭包和装饰器的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 软件测试/测试开发丨Python 内置库 正则表达式

    本文为霍格沃兹测试开发学社学员学习笔记分享 原文链接:https://ceshiren.com/t/topic/27058 正则表达式 使用re模块实现正则表达式操作 正则表达式就是记录文本规则的代码 可以查找操作符合某些复杂规则的字符串 把正则表达式作为模式字符串 正则表达式可以使用原生字符串来表

    2024年02月10日
    浏览(69)
  • Python笔记三之闭包与装饰器

    本文首发于公众号:Hunter后端 原文链接:Python笔记三之闭包与装饰器 这一篇笔记介绍 Python 里面的装饰器。 在介绍装饰器前,首先提出这样一个需求,我想统计某个函数的执行时间,假设这个函数如下: 想要统计 add 函数的执行时间,可以如何操作,在一般情况下,可能会

    2024年02月03日
    浏览(44)
  • 【python高级用法】迭代器、生成器、装饰器、闭包

    可迭代对象:可以使用for循环来遍历的,可以使用isinstance()来测试。 迭代器:同时实现了__iter__()方法和__next__()方法,可以使用isinstance()方法来测试是否是迭代器对象 使用类实现迭代器 两个类实现一个迭代器 一个类实现迭代器 可迭代对象与迭代器的总结 一个具备了__iter_

    2024年02月03日
    浏览(37)
  • 【自然语言处理】NLP入门(一):1、正则表达式与Python中的实现(1):字符串构造、字符串截取

       语言 是一种使用具有共同处理规则的沟通指令的广义概念,这些指令可以通过视觉、声音或触觉等方式传递。语言可以分为自然语言、动物语言和计算机语言。    自然语言 是人类发展过程中形成的一种信息交流方式,它包括口语和书面语,并且反映了人类的思想。

    2024年03月12日
    浏览(142)
  • 【正则表达式】正则表达式常见匹配模式

    模式 描述 w 匹配字母数字及下划线 W 匹配非字母数字下划线 s 匹配任意空白字符,等价于 [tnrf]. S 匹配任意非空字符 d 匹配任意数字,等价于 [0-9] D 匹配任意非数字 A 匹配字符串开始 Z 匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串 z 匹配字符串结

    2024年02月09日
    浏览(78)
  • 【Go 基础篇】Go语言匿名函数详解:灵活的函数表达式与闭包

    在Go语言中,函数是一等公民,这意味着函数可以像其他类型的值一样被操作、传递和赋值。匿名函数是一种特殊的函数,它没有固定的函数名,可以在代码中被直接定义和使用。匿名函数在Go语言中具有重要的地位,它们常用于实现闭包、函数式编程和并发编程等领域。 本

    2024年02月11日
    浏览(51)
  • Django-带参数的路由编写(一)【不用正则表达式匹配的简单带参数路由】

    在某urls.py文件有如下的路由配置语句: 语句: 中的 int:id 就是带参数的URL中的参数部分,其语法格式如下: 参数数据类型:参数名称 URL参数有4种数据类型,如下表所示: 提问: Django的URL参数中的str类型和slug类型有什么区别?感觉都是对字符串的匹配啊! 答: 在Django中,

    2024年02月10日
    浏览(38)
  • 正则表达式2 常见模式

     继上次的正则表达式速攻1/2-CSDN博客 还有一些常见的匹配模式可以直接使用 电子邮箱  xxx@xxx.域名 的情况 http或者https网址 的情况 IPV4地址 例如 192.168.1.1 匹配日期的情况 xxxx/xx/xx 或者  xxxx-xx-xx 匹配整数或者小数  例如 3.14 RGB颜色   例如 #aabbcc  #ffffff

    2024年01月17日
    浏览(55)
  • Python 知识体系补全(闭包、装饰器、关键字参数**kwargs,位置参数*args)

    闭包:     什么是闭包,一句话,在函数中再嵌套一个函数,并且引用外部函数的变量,这就是一个闭包了     一般外部函数的返回值为内部函数      def outer(x):          def inner(y):              return x + y         return outer     # 外部函数的返回值,是内部函数     

    2024年02月06日
    浏览(40)
  • 正则表达式:贪婪与非贪婪模式

    正则中的三种模式,贪婪匹配、非贪婪匹配和独占模式。 在这 6 种元字符中,我们可以用 {m,n} 来表示 (*)(+)(?) 这 3 种元字符: 贪婪模式,简单说就是尽可能进行最长匹配。非贪婪模式呢,则会尽可能进行最短匹配。正是这两种模式产生了不同的匹配结果。 贪婪匹配

    2024年02月12日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包