装饰器函数中的变量如何访问其范围之外的值?

时间:2017-11-19 10:02:50

标签: python python-3.x generator

以下是一个样本装饰器:

def smart_divide(func):
   def inner(a,b):
      print("I am going to divide",a,"and",b)
      if b == 0:
         print("Whoops! cannot divide")
         return

      return func(a,b)
   return inner

@smart_divide
def divide(a,b):
    return a/b

如果func是一个对象,那么如何从中访问变量ab

是不是想要这样做?

def func(potato):
      print(y, x)

我有没有得到一个基本概念?这里发生的事情是Python中某些模式的一部分,还是ab知道的特殊情况,因为它是一个生成器?

更新

another stack exchange answer

的新示例
def my_shiny_new_decorator(a_function_to_decorate):

    def the_wrapper_around_the_original_function():

        print("Before the function runs")

        a_function_to_decorate()

        print("After the function runs")

    return the_wrapper_around_the_original_function

def a_stand_alone_function():
    print("I am a stand alone function, don't you dare modify me")

发电机手动方式

a_stand_alone_function = my_shiny_new_decorator(a_stand_alone_function)
a_stand_alone_function()

发电机正确的方式

@my_shiny_new_decorator
def another_stand_alone_function():
    print("Leave me alone")

根据我从“手动”方式获得新答案的地方,“正确方式”是相同的。

我认为这个例子可能会让我陷入困境,因为我试图将其扩展到涉及参数时。

我现在意识到我想象的没有意义

我认为我发布的原始代码与此相同

divide = smart_divide(divide(a,b))

如果执行将看起来像这样

def smart_divide(divide(a,b)):
   def inner(a,b):
      print("I am going to divide",a,"and",b)
      if b == 0:
         print("Whoops! cannot divide")
         return

      return func(a,b)
   return inner

但这会导致div(a,b)在顶行执行

新示例中的

'a_stand_alone_function'末尾没有()。这意味着它被视为一个对象。

所以我对它看起来像这个def smart_divide(divide(a,b)):的想法没有意义,因为该函数不再被视为一个对象

这让我对smart_devide如何获取作为参数传递的信息感到困惑。

2 个答案:

答案 0 :(得分:2)

不,你的装饰师会返回inner作为divide的新实现。因此,当程序执行inner时,首先调用函数divide(1, 2)。致divide的来电始终尊重inner的签名(并在代码中划分)。

这样的功能
def divide(a, b):  # signature
    return a / b   # implementation or body

由两部分组成。签名描述了参数以及函数的实现。

你的装饰者只会修改你的功能的实现,如下所示:

def divide(a, b):                            # signature remains unmodified
    print("I am going to divide",a,"and",b)  # implementation of inner
    if b == 0:
        print("Whoops! cannot divide")
        return
    return a / b                             # call to the original implementation of divide   

divide的名称和签名保持不变。因此,inner的签名很重要,而不是装饰者的签名。

答案 1 :(得分:2)

smart_divide 没有获取ab。它返回一个函数对象(inner函数), 函数获取a并将b传递给 it

如果您尝试这样做,您可以看到实际发生的事情:

def smart_divide(func):
   print("I am running in smart_divide; func=", func)
   def inner(a,b):
      print("I am going to divide",a,"and",b)
      if b == 0:
         print("Whoops! cannot divide")
         return

      return func(a,b)
   print("I am returning from smart_divide")
   return inner

print("I am running at top level before declaring divide")

@smart_divide
def divide(a,b):
    return a/b

print("The name 'divide' now refers to", divide)

print("I am now going to call the divide function")
divide(1, 2)

输出:

I am running at top level before declaring divide
I am running in smart_divide; func= <function divide at 0x108ff2bf8>
I am returning from smart_divide
the name 'divide' now refers to <function smart_divide.<locals>.inner at 0x10565db70>
I am now going to call the divide function
I am going to divide 1 and 2