精华内容
下载资源
问答
  • python函数修饰器

    2019-08-02 22:12:24
    python函数修饰器 什么是修饰器? 修饰器是一个函数,接受一个函数或方法作为其唯一的参数,并返回一个新函数或方法,其中整合了修饰后的函数或方法,并附带了一些额外的功能.1 上面的定义不免有点难以理解,我们来看下面...

    python函数修饰器

    什么是修饰器?

    修饰器是一个函数,接受一个函数或方法作为其唯一的参数,并返回一个新函数或方法,其中整合了修饰后的函数或方法,并附带了一些额外的功能.1

    上面的定义不免有点难以理解,我们来看下面的图
    修饰器的形象图

    我们之前所理解的python执行函数过程是如图1.1的流程.

    如果我们给函数添加了修饰器,那么当程序执行到函数A的时候,系统会检测到函数A上有一个修饰器,那么系统就会先执行修饰器里的过程然后再回到函数执行函数的内容.

    但是从修饰器回来的那一条线路其实并不是必须的, 需要在修饰器里面编写回来的语句回到函数,接下来会讲到

    修饰器的简单作用

    在其定义中就已经介绍修饰器的作用是给函数增加额外的功能.

    : 在修饰器的简单作用这一部分,接下来的内容我无法自己组织语言将其讲清楚,故参考了简书作者MrYun 谈谈python修饰器 的内容,个人觉得这一篇在引入修饰器作用方面的描写很棒!

    从简单的一个例子讲起,现在我们有一个函数

    def foo():
        print("this is a test")
    
    foo()
    

    现在我们需要给它进行性能测试,那么需要改成以下内容

    import time
    
    
    def foo():
        start = time.clock()
        print("this is a test")
        end = time.clock()
        print("start:", start, " end:", end)
    
    
    foo()
    

    如果我们希望给几十上百个函数都添加这样的性能测试,那么需要在每个函数内部开头与结尾都这样编辑吗?显然不是.

    这个时候我们编写一个新的函数test(),在test的函数开头与结尾编写时间定义,将要测试的函数传入test的函数(函数也是一个变量,是可以作为参数的),在中间执行,比如以下内容

    import time
    
    
    def foo():
        print("this is a test")
    
    
    def test(func):
        start = time.clock()
        foo()
        end = time.clock()
        print("start:", start, " end:", end)
    
    
    test(foo)
    

    现在我们就可以给每个函数进行测试了

    for 函数 in 项目:
        test(函数)
    

    如果我们将test中的输出加入到文件中,我们就可以得到每个函数的性能记录

    但是, 现在我们需要给大量函数实现另一个功能: 日志功能, 也就是在项目执行过程中, 函数的每一个操作都被记录下来, 意味着每使用一次函数都要手动编写test(foo), 尤其是如果需要使用函数的返回值的时候, 这种方式就有点捉襟见肘了

    这个时候修饰器的作用就显示出来了. 它可以在每个使用它的函数上进行功能的添加, 而且使用者完全感受不到他的存在, 也就是说我们使用的时候依然是foo(), 但是在内部项目却另外实现了test()的功能

    这个修饰器的使用格式如下,具体内容之后会讲解

    import time
    
    
    def test(func):
        def wrapper():
            start = time.clock()
            func()
            end = time.clock()
            print("start:", start, " end:", end)
        return wrapper
    
    
    @test
    def foo():
        print("this is a test")
    
    
    foo()
    

    修饰器的使用

    上面已经了解到了修饰器的作用,那么我们可以了解修饰器的格式了.

    上面插入的修饰器太过突兀,我们来段过渡代码(这一段代码也是来自那篇简书)

    import time
    
    def test(func):
        def wrapper():
            start = time.clock()
            func()
            end = time.clock()
            print("start:", start, " end:", end)
        return wrapper
    
    def foo():
        print("this is a test")
    
    
    foo = test(foo)
    foo()
    

    执行过程可以这样理解:

    foo = test(foo)

    foo() = test(foo)() = wrapper()
    装饰器执行过程
    在python中, 我们把foo = test(foo)用一种更简单的形式来表达, 就是在使用装饰器的函数foo上面加上 @修饰器名称, python的修饰器是一种语法糖.

    @test
    def foo():
        print("this is a test")
    

    如果需要使用到foo函数的返回值,那么test函数可以这样写

    import time
    def test(func):
        def wrapper():
            start = time.clock()
            print("this is a order test, if you need not it, delete it") # 用于测试执行顺序,可以跟着走一遍
            a = func()
            end = time.clock()
            print("start:", start, " end:", end)
            return a # 这种获得返回值的方法可能在多层修饰器的时候有矛盾,我先用!!!标记, 等理顺后再回来修改,如果我发布之后这里依然存在...说明我忘记了...
        return wrapper
    
    @test
    def foo():
        print("this is a test")
        return "this is a return value"
    
    print(foo())
    # 输出
    # this is a test wrapper, if you need not it, delete it
    # this is a test
    # start: 4.44444839506524e-07  end: 1.8222238419767486e-05
    # this is a return value
    

    在《Python3程序开发指南第二版》(以下简称《指南》)中给的例子是一个对python初学者(没涉及项目)来说比较有趣的小修饰器, 有兴趣可以看看,我给它做了一点注释

    def positive_result(function):
        def wrapper(*args, **kwargs):
            # result获得函数的返回值, 进行结果判断
            result = function(*args, **kwargs)
            # assert断言, 如果function函数的返回值大于等于0, 的产生一个AssertionError异常
            assert result >= 0, function.__name__ + "() result isn't >= 0"
            # 返回
            return result
        
        # 将wrapper的docstring和名称设置成和原始函数一样,有利于内省(获得自身的信息)
        wrapper.__name__ = function.__name__ 
        wrapper.__doc__ = function.__doc__
        return wrapper
    
    # 使用positive_result修饰器
    @positive_result
    def discriminant(a,b,c):
        return (b**2) - (4*a*c)
    
    
    print(discriminant(0,6,5))
    print(discriminant(2,6,5))
    

    执行过程可以这样理解:

        discriminant = positive_result(discriminant)
    
        discriminant(a,b,c) = positive_result(discriminant)(a,b,c) = wrapper(a, b, c)
    

    《指南》中给出了这个例子的简化版, 使用到了functools.wraps(function)

    def positive_result(function):
        # wrapper本身使用functools模块的@functools.wraps进行包裹, 这可以确保wrapper的名称与docstring与function相同
        @functools.wraps(function)
        def wrapper(*args, **kwargs):
            result = function(*args, **kwargs)
            assert result >= 0, function.__name__ + "() result isn't >= 0"
    
            return result
        return wrapper
    
    

    修饰器参数化

    现在我们已经了解到了什么是修饰器以及修饰器的基本使用, 那么在上面的日志修饰器上, 我们的日志信息往往是要写入文件内,但是不同的函数需要写进的文件名不一样, 那么简单的 @修饰器名称已经没法满足需要了, 这个时候就需要修饰器参数化, 即将要操作的文件名传递给test()函数

    现在放一个《指南》中给出的例子

    import functools
    def bounded(mininum, maxinum):
        def decorator(function):
            @functools.wraps(function)
            def wrapper(*args, **kwargs):
                result = function(*args, **kwargs)
                if result < mininum:
                    return mininum
                elif result > maxinum:
                    return maxinum
                return result
            return wrapper
        return decorator
    
    @bounded(0,100)
    def percent(amount, total):
        return (amount / total) * 100
    
    percent(15,100)
    
    • 执行过程如下
      带参数装饰器执行过程
      执行过程可以这样理解

        percent = bounded(mininum, maxinum)(percent)
      
        percent(amount, total) = bounded(mininum, maxinum)(percent)(amount, total) = wrapper(amount, total)
      

    与普通装饰器的对比:
    带参数装饰器与普通装饰器对比


    1. 《Python3程序开发指南第二版》第八章P311 ↩︎

    展开全文
  • Python 函数修饰器

    2018-09-04 20:17:15
    对于修饰器的传入参数prefix,修饰器不会立即将带待修饰的函数作为参数传入完成修饰,而是先做了一个预处理,返回了一个_deco函数,而这个_deco函数才是真正被f函数调用的修饰器。           ...

    例1:

    def deco(func):
        def wrappedFunc():
            return "Hello World_"+func()
        return wrappedFunc#很恶心
    
    @deco
    def f():
        return  "I am f"
    
    def g():
        return "I am g"
    
    print(f())
    print(g())

    运行结果:

    例2:

    def deco(prefix):
        def _deco(func):
            def wrappedFunc():
                return prefix+func()
            return wrappedFunc
        return _deco
    
    @deco("second_")
    @deco("first_")
    def f():
        return "I am f"
    
    print(f())

    运行结果:

    deco函数和wrappedFunc函数之间增加了一个_deco函数,这是为了处理deco函数传入的prefix参数。对于修饰器的传入参数prefix,修饰器不会立即将带待修饰的函数作为参数传入完成修饰,而是先做了一个预处理,返回了一个_deco函数,而这个_deco函数才是真正被f函数调用的修饰器。

     

     

     

     

     

     

     

     

    展开全文
  • python语言本身具有丰富的功能和表达语法,其中修饰器是一个非常有用的功能。在设计模式中,decorator能够在无需直接使用子类的方式来动态地修正一个函数,类或者类的方法的功能。当你希望在不修改函数本身的前提下...

    python语言本身具有丰富的功能和表达语法,其中修饰器是一个非常有用的功能。在设计模式中,decorator能够在无需直接使用子类的方式来动态地修正一个函数,类或者类的方法的功能。当你希望在不修改函数本身的前提下扩展函数的功能时非常有用。

    简单地说,decorator就像一个wrapper一样,在函数执行之前或者之后修改该函数的行为,而无需修改函数本身的代码,这也是修饰器名称的来由。

    关于函数

    在Python中,函数是first class citizen,函数本身也是对象,这意味着我们可以对函数本身做很多有意义的操作。

    将函数赋值给变量:

    def greet(name):
        return "hello "+name
    
    greet_someone = greet
    print greet_someone("John")
    
    # Outputs: hello John

    函数内定义函数:

    def greet(name):
        def get_message():
            return "Hello "
    
        result = get_message()+name
        return result
    
    print greet("John")
    
    # Outputs: Hello John

    函数可以作为参数传给其他函数:

    def greet(name):
       return "Hello " + name 
    
    def call_func(func):
        other_name = "John"
        return func(other_name)  
    
    print call_func(greet)
    
    # Outputs: Hello John

    函数可以返回其他函数(函数产生函数):

    def compose_greet_func():
        def get_message():
            return "Hello there!"
    
        return get_message
    
    greet = compose_greet_func()
    print greet()
    
    # Outputs: Hello there!

    内部函数可以访问外部包scope(enclosing scope)

    def compose_greet_func(name):
        def get_message():
            return "Hello there "+name+"!"
    
        return get_message
    
    greet = compose_greet_func("John")
    print greet()
    
    # Outputs: Hello there John!

    需要注意的是:这种情况下python仅仅允许"只读"访问外部scope的变量

    开始创作我们的decorator

    函数的修饰器就是已知函数的wrapper.将上述函数的好功能运用起来就能制作我们的decorator.

    def get_text(name):
       return "lorem ipsum, {0} dolor sit amet".format(name)
    
    def p_decorate(func):
       def func_wrapper(name):
           return "<p>{0}</p>".format(func(name))
       return func_wrapper
    
    my_get_text = p_decorate(get_text)
    
    print my_get_text("John")
    
    # <p>Outputs lorem ipsum, John dolor sit amet</p>

    这就是我们的第一个修饰器。一个函数接收另一个函数作为参数,并且产生一个新的函数,修正参数函数的功能并添加新功能,并且返回一个"generated"新函数,这样我们后面就可以在任何地方使用这个新创建的函数了。我们也可以将修饰器函数直接赋值给参数函数名本身,这样就覆盖了原来的函数!

    get_text = p_decorate(get_text)
    
    print get_text("John")
    
    # Outputs lorem ipsum, John dolor sit amet

    另外一点需要注意的是:被修饰的函数get_text具有一个name参数,我们必须在wrapper函数中传入那个参数。

    python的修饰符语法糖

    在上面的例子中我们通过get_text=p_decorate(get_text)的方式覆盖了get_text从而形成了有新功能的同名函数,这个显得有点啰嗦,python提供了简洁清晰的对应语法。比如:

    def p_decorate(func):
       def func_wrapper(name):
           return "<p>{0}</p>".format(func(name))
       return func_wrapper
    
    @p_decorate
    def get_text(name):
       return "lorem ipsum, {0} dolor sit amet".format(name)
    
    print get_text("John")
    
    # Outputs <p>lorem ipsum, John dolor sit amet</p>

    在上面的例子代码中,@符号后面的是修饰器本身,紧跟后面的则是将被修饰的函数(将隐含着赋值覆盖操作)。这种语法等价于使用@后面的修饰器先对get_text修饰,并且返回产生的新函数替代被修饰的函数名。后面直接用被修饰的函数名调用,但是却有了新的功能!

    现在,我们希望再添加两个其他的函数来修饰get_text分别再增加一个div和strong tag

    def p_decorate(func):
       def func_wrapper(name):
           return "<p>{0}</p>".format(func(name))
       return func_wrapper
    
    def strong_decorate(func):
        def func_wrapper(name):
            return "<strong>{0}</strong>".format(func(name))
        return func_wrapper
    
    def div_decorate(func):
        def func_wrapper(name):
            return "<div>{0}</div>".format(func(name))
        return func_wrapper
    
    # 基础用法:
    get_text = div_decorate(p_decorate(strong_decorate(get_text)))
    #等价于:
    @div_decorate
    @p_decorate
    @strong_decorate
    def get_text(name):
       return "lorem ipsum, {0} dolor sit amet".format(name)
    
    print get_text("John")
    
    # Outputs <div><p><strong>lorem ipsum, John dolor sit amet</strong></p></div>

    需要注意的是修饰器的顺序是有关系的。如果顺序不同,则结果也不同。

    method修饰

    python中类的方法是一个首参数为self指针的函数。我们可以和普通函数一样去做修饰,但是需要注意的是必须在wrapper函数中考虑self指针参数。

    def p_decorate(func):
       def func_wrapper(self):
           return "<p>{0}</p>".format(func(self))
       return func_wrapper
    
    class Person(object):
        def __init__(self):
            self.name = "John"
            self.family = "Doe"
    
        @p_decorate
        def get_fullname(self):
            return self.name+" "+self.family
    
    my_person = Person()
    print my_person.get_fullname()

    一个更好的方案是调整代码使得我们的修饰器对于函数或者method同样适用。这可以通过通过将args和*kwargs放到wrapper函数中作为参数来实现,这样可以接受任意个数的参数或者keyword型参数。

    def p_decorate(func):
       def func_wrapper(*args, **kwargs):
           return "<p>{0}</p>".format(func(*args, **kwargs))
       return func_wrapper
    
    class Person(object):
        def __init__(self):
            self.name = "John"
            self.family = "Doe"
    
        @p_decorate
        def get_fullname(self):
            return self.name+" "+self.family
    
    my_person = Person()
    
    print my_person.get_fullname()

     向decorator传入参数

    def tags(tag_name):
        def tags_decorator(func):
            def func_wrapper(name):
                return "<{0}>{1}</{0}>".format(tag_name, func(name))
            return func_wrapper
        return tags_decorator
    
    @tags("p")
    def get_text(name):
        return "Hello "+name
    
    print get_text("John")
    
    # Outputs <p>Hello John</p>

    在这个例子中,貌似又更加复杂了一点,但是带来了更多的灵活性。decorator必须仅接受一个被修饰的函数为参数,这也是为什么我们必须再外包裹一层从而接受那些额外的参数并且产生我们的decorator的原因。这个例子中tags函数是我们的decorator generator

    调试decorated function

    从上面的描述可知,decorators负责包裹被修饰的函数,这带来一个问题就是如果要调试代码可能有问题,因为wrapper函数并不会携带原函数的函数名,模块名和docstring等信息,比如基于以上的例子,如果我们打印get_text.__name__则返回func_wrapper而不是get_text,原因就是__name__,__doc__,__module__这些属性都被wrapper函数所(func_wrapper)重载。虽然我们可以手工重置(在func_wrapper),但是python提供了更好的办法:

    functools

    functools模块包含了wraps函数。wraps也是一个decorator,但是仅仅用于更新wrapping function(func_wrapper)的属性为原始函数的属性(get_text),看下面的代码:

    from functools import wraps
    
    def tags(tag_name):
        def tags_decorator(func):
            @wraps(func)
            def func_wrapper(name):
                return "<{0}>{1}</{0}>".format(tag_name, func(name))
            return func_wrapper
        return tags_decorator
    
    @tags("p")
    def get_text(name):
        """returns some text"""
        return "Hello "+name
    
    print get_text.__name__ # get_text
    print get_text.__doc__ # returns some text
    print get_text.__module__ # __main__

    何时使用decorator?

    在上面的例子中仅仅罗列了修饰器的基础用法,实际上这个机制是非常强大有用的,总的来说,decorator在你希望在不修改函数本身代码的前提下扩展函数的功能时非常有用。

    一个经典的例子timeout修饰函数:

    https://wiki.python.org/moin/PythonDecoratorLibrary#Function_Timeout

    timeout修饰符产生函数的定义:

    import signal
    import functools
    
    class TimeoutError(Exception): pass
    
    def timeout(seconds, error_message = 'Function call timed out'):
        def decorated(func):
            def _handle_timeout(signum, frame):
                raise TimeoutError(error_message)
    
            def wrapper(*args, **kwargs):
                signal.signal(signal.SIGALRM, _handle_timeout)
                signal.alarm(seconds)
                try:
                    result = func(*args, **kwargs)
                finally:
                    signal.alarm(0)
                return result
    
            return functools.wraps(func)(wrapper)
    
        return decorated

    使用:

    import time
    
    @timeout(1, 'Function slow; aborted')
    def slow_function():
        time.sleep(5)

     

    https://www.thecodeship.com/patterns/guide-to-python-function-decorators/

    https://wiki.python.org/moin/PythonDecoratorLibrary

     

     

     

    转载于:https://www.cnblogs.com/kidsitcn/p/9413273.html

    展开全文
  • import time ...#计算func函数的执行时间。 def cal(func): def inner(): print("inner()函数开始...") start = time.time() print("开始时间:"+str(start)) func() end = time.time() ...
    import time
    
    #计算func函数的执行时间。
    def cal(func):
        def inner():
            print("inner()函数开始...")
            start = time.time()
            print("开始时间:"+str(start))
    
            func()
    
            end = time.time()
            print("结束时间:"+str(end))
            print("函数执行耗时:"+str(end - start))
        return inner
    
    
    @cal
    def foo():
        print('foo 函数')
    
    foo()

     

    输出:

    inner()函数开始...
    开始时间:1557489795.7333722
    foo 函数
    结束时间:1557489795.7383566
    函数执行耗时:0.004984378814697266

    Python的函数修饰器很有用,比如现在有些需求要埋点统计某些函数的执行时间耗时,即面向切面编程,利用Python函数的@修饰器,可以轻松的得到统计结果,比如本例的函数执行耗时统计。

    展开全文
  •  Python中的函数是对象。也因此,函数可以被当做变量使用。 二、代码模型 以下代码片段来自于: http://www.sharejs.com/codes/python/8361 # -*- coding: utf-8 -*- from threading import Thread import time ...
  • Python函数修饰符(装饰)的使用1.修饰符的来源修饰符是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志、性能测试、事务处理等。修饰符是解决这类问题的绝佳设计,有了修饰符,我们就...
  • 有很多初学者对函数修饰器有一种懵逼的感觉,这东西到底干什么的,怎么用。如果你也有同样的问题,很正常,我们来聊聊函数装饰器。函数装饰器是python语法中一个重要的编程技巧,想发挥出python的优雅写法,必须掌握...
  • python自定义函数修饰器的格式和引用如下: 首先定义一个函数: def xxx1: xxxx 然后在需要用到函数修饰器的函数上方是使用@xxx1的方式对该函数进行修饰: @xxx1 def helloWork(): xxxxx @修饰函数,实际...
  • python @ 函数修饰器

    2020-05-30 17:00:30
    函数修饰器大概分为两种: 带参数的函数修饰 不带参数的函数修饰 1. 带参数的函数修饰 用funA() 函数装饰器,去装饰 funB() 被修饰的函数 def funA(fn): print('A q前') fn() print('A 后') return 'A return...
  • python函数修饰符@

    2021-05-14 21:41:15
    带参的函数修饰器:在修饰函数内继续嵌套函数,嵌套函数以def func(*args,**kwargs)的形式出现 在修饰函数内部的返回值就是被修饰函数的返回值 被修饰函数的.__name__属性会变成修饰函数的嵌套函数的.__...
  • 主要介绍了Python使用修饰器执行函数的参数检查功能,结合具体实例形式分析了Python实现修饰器针对函数参数检查的原理、步骤与相关操作技巧,需要的朋友可以参考下
  • Python 函数修饰符(装饰)的学习 import time class Test: def __init__(self): self.name='' self.functionDict = {} def msg_register(self, msgType, isFriendChat=False, isGroup
  • python函数修饰符@总结

    千次阅读 2018-09-06 11:19:37
    Python函数修饰符:”@”。通过decorator装饰模式,使得代码更简单。 1)函数必须先定义再修饰 2)修饰符”@”后面必须是之前定义的某一个函数 3)每个函数只能有一个修饰符   常规修饰符 除去某些特定字符...
  • python函数修饰符@的作用是为现有函数增加额外的功能,常用于插入日志、性能测试、事务处理等等。 创建函数修饰符的规则: (1)修饰符是一个函数 (2)修饰符取被修饰函数为参数 (3)修饰符返回一个新函数 (4)...
  • Python 函数修饰符(装饰)的使用 1.修饰符的来源修饰符是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志、性能测试、事务处理等。 修饰符是解决这类问题的绝佳设计,有了修饰符,...
  • 本文实例讲述了Python使用修饰器执行函数的参数检查功能。分享给大家供大家参考,具体如下:参数检查:1. 参数的个数;2. 参数的类型;3. 返回值的类型。考虑如下的函数:import htmldef make_tagged(text, tag):...
  • a = <function a at 0x___________________> b = 123 Process finished with exit code 0 总结 @ 符号的效果是将被修饰函数传递给调用函数,再将处理后的值返回给被修饰函数 Here: a() 为调用函数;b() 为被修饰...
  • python中的函数修饰器

    2018-03-14 11:53:32
    python中的函数修饰器 – @wrapper 简介 类似于C#的属性、Java的注解,python也有对应的修饰符。从Python2.7和Python3开始,提供了以’@’为标示的修饰符,可以在模块或者类的定义层次内对函数进行修饰。 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 25,523
精华内容 10,209
关键字:

python函数修饰器

python 订阅