【问题标题】:Python decorator for function subsegments函数子段的 Python 装饰器
【发布时间】:2018-12-01 18:25:20
【问题描述】:

在 Python 中,有没有一种很好的方法可以将装饰器(或类似的东西)应用到函数体的子段而不是整个函数?

我想要的可能看起来像这样:

def deco_double(f):
    def wrapper():
            f()
            f()
    return wrapper

def foo():
    @deco_double:
        print("hello")
        print("stack")
    @deco_double:
        print("overflow")

foo()

所以执行结果是这样的:

hello
stack
hello
stack
overflow
overflow

如果解决方案不完全是装饰器也没关系,我需要的是一种包装函数子段的方法,但要以一种很好的抽象方式。提前谢谢你:)

编辑: 仅仅分成多个功能对我来说不是一个选择。我正在为程序员开发一个框架,我希望他们以紧凑的方式编写函数(用于在示例中编写 foo()。另外,我实际所做的远比重复要复杂得多)

edit2: 到目前为止,我似乎别无选择,只能期望框架用户以某种方式声明命名函数......

【问题讨论】:

  • 只是使用更多的功能。
  • 你说分离成多个功能不是一种选择,然后在你接受的答案中你继续这样做。

标签: python decorator python-decorators


【解决方案1】:

函数体被编译成一个整体运行的“代码”对象——改变这个代码对象的运行方式,在其中插入东西,这些东西可能和语言代码本身一样复杂(即实际“执行”Python 字节码的代码)。

因此,执行流程中的任何更改都可以通过使用已经执行此操作的语言中的语句来轻松完成。

如果你想在函数体内的部分中使用通用装饰器,最简单的方法是将函数本身细分为内部函数 - 然后你可以应用你的转换,或者多次执行每个部分,只需调用这些函数(甚至直接装饰它们)。

但是,如果您提出问题,您可以并且可能应该只使用一个普通的旧 for 循环:

def foo():
    for _ in (0, 1):
        print("hello")
        print("stack")
    for _ in (0, 1):
        print("overflow")

对于任意“类似装饰器的行为”,正如我在上面所写的,只需使用嵌套函数:

def foo():
    @deco_double
    def part1()
        print("hello")
        print("stack")
    part1()
    @deco_double:
    def part2():
        print("overflow")
    part2()

【讨论】:

  • 感谢您对 Python 代码执行的解释 :) 我实际上所做的不仅仅是循环。简洁是我正在制作的东西(一个框架)的关键,所以我认为 lambda 表达式比嵌套函数更适合我的要求。
  • 好的,现在我意识到没有多行 lambda 表达式。我认为这是一个更好的选择。
  • 此外,通常用于此类内容的部分是with 语句和上下文管理器协议。虽然它可以处理很多进入和离开代码块的事情,但它不能改变代码块要按顺序执行一次 - 这就是我在答案中没有提到它的原因。
【解决方案2】:

您必须提取 foo() 的部分功能以分离函数,然后将装饰器作为函数应用并显式调用它。

def deco_double(f):
    def wrapper():
            f()
            f()
    return wrapper

def my_f1():
     print("hello")
     print("stack")

def my_f2():
     print("overflow")

def foo():
    deco_double(my_f1)()
    deco_double(my_f2)()

foo()

【讨论】:

    【解决方案3】:

    只需使用装饰器@deco_double 声明两个具有任何名称的函数,然后在任何其他函数中调用它们,在您的情况下为foo(),然后只需调用foo()

    def deco_double(f):
        def wrapper():
                f()
                f()
        return wrapper
    @deco_double
    def func1():
         print("hello")
         print("stack")
    @deco_double
    def func2():
         print("overflow")
    def foo():
        func1()
        func2()
    foo()
    

    此代码的输出。

    hello
    stack
    hello
    stack
    overflow
    overflow
    

    【讨论】:

      【解决方案4】:

      如果您想实现此目的,您可能需要使用 lambda 传递函数:

      def doubler(f):
        f()
        f()
      
      def foo():
        doubler(lambda: print("hello"))
      
        doubler(lambda: print("world"))
      
      foo()
      "hello"
      "hello"
      "world"
      "world"
      

      将要运行两次的代码包装在lambda中,并将函数传递给doubler

      【讨论】:

      • 我想使用 lambda 表达式是我必须考虑的,谢谢!!
      • 它们通常有助于概括代码和减少重复。
      • 我认为应该指出的是,这个解决方案也可以与普通函数一起使用,并且仍然比其他答案更简洁,因为您不需要考虑命名函数(@987654325 @ 会做),您不必单独调用它们。
      • 现在我发现多行 lambda 表达式是不可能的......如果这仅限于单行,我想我不能使用它。对不起
      • @Silvershine157 是的。这是 Python 的一个非常不幸的限制。
      猜你喜欢
      • 2019-12-18
      • 2019-07-09
      • 2014-07-21
      • 2017-09-14
      • 2020-07-13
      • 2012-11-12
      • 2016-09-27
      • 1970-01-01
      • 2015-09-17
      相关资源
      最近更新 更多