装饰器原理

装饰器(Decorators)是 Python 的一个重要部分。简单地说:他们是修改其他函数的功能的函数。他们有助于让我们的代码更简短,也更 Pythonic(Python范儿)。大多数初学者不知道在哪儿使用它们,所以我将要分享下,哪些区域里装饰器可以让你的代码更简洁。

首先,让我们讨论下如何写你自己的装饰器。

这可能是最难掌握的概念之一。我们会每次只讨论一个步骤,这样你能完全理解它。

一切皆对象

首先我们来理解下 Python 中的函数

  1. def hi(name="yasoob"):
  2. return "hi " + name
  3. print(hi())
  4. # output: 'hi yasoob'
  5. # 我们甚至可以将一个函数赋值给一个变量,比如
  6. greet = hi
  7. # 我们这里没有在使用小括号,因为我们并不是在调用hi函数
  8. # 而是在将它放在greet变量里头。我们尝试运行下这个
  9. print(greet())
  10. # output: 'hi yasoob'
  11. # 如果我们删掉旧的hi函数,看看会发生什么!
  12. del hi
  13. print(hi())
  14. #outputs: NameError
  15. print(greet())
  16. #outputs: 'hi yasoob'

在函数中定义函数

刚才那些就是函数的基本知识了。我们来让你的知识更进一步。在 Python 中我们可以在一个函数中定义另一个函数:

  1. def hi(name="yasoob"):
  2. print("now you are inside the hi() function")
  3. def greet():
  4. return "now you are in the greet() function"
  5. def welcome():
  6. return "now you are in the welcome() function"
  7. print(greet())
  8. print(welcome())
  9. print("now you are back in the hi() function")
  10. hi()
  11. #output:now you are inside the hi() function
  12. # now you are in the greet() function
  13. # now you are in the welcome() function
  14. # now you are back in the hi() function
  15. # 上面展示了无论何时你调用hi(), greet()和welcome()将会同时被调用。
  16. # 然后greet()和welcome()函数在hi()函数之外是不能访问的,比如:
  17. greet()
  18. #outputs: NameError: name 'greet' is not defined

那现在我们知道了可以在函数中定义另外的函数。也就是说:我们可以创建嵌套的函数。现在你需要再多学一点,就是函数也能返回函数。

从函数中返回函数

其实并不需要在一个函数里去执行另一个函数,我们也可以将其作为输出返回出来:

  1. def hi(name="yasoob"):
  2. def greet():
  3. return "now you are in the greet() function"
  4. def welcome():
  5. return "now you are in the welcome() function"
  6. if name == "yasoob":
  7. return greet
  8. else:
  9. return welcome
  10. a = hi()
  11. print(a)
  12. #outputs: <function greet at 0x7f2143c01500>
  13. #上面清晰地展示了`a`现在指向到hi()函数中的greet()函数
  14. #现在试试这个
  15. print(a())
  16. #outputs: now you are in the greet() function

再次看看这个代码。在 if/else 语句中我们返回 greetwelcome,而不是 greet()welcome()。为什么那样?这是因为当你把一对小括号放在后面,这个函数就会执行;然而如果你不放括号在它后面,那它可以被到处传递,并且可以赋值给别的变量而不去执行它。

你明白了吗?让我再稍微多解释点细节。

当我们写下 a = hi()hi() 会被执行,而由于 name 参数默认是 yasoob,所以函数 greet 被返回了。如果我们把语句改为 a = hi(name = "ali"),那么 welcome 函数将被返回。我们还可以打印出 hi()(),这会输出 now you are in the greet() function

将函数作为参数传给另一个函数

  1. def hi():
  2. return "hi yasoob!"
  3. def doSomethingBeforeHi(func):
  4. print("I am doing some boring work before executing hi()")
  5. print(func())
  6. doSomethingBeforeHi(hi)
  7. #outputs:I am doing some boring work before executing hi()
  8. # hi yasoob!

现在你已经具备所有必需知识,来进一步学习装饰器真正是什么了。装饰器让你在一个函数的前后去执行代码。