Home  >  Article  >  Backend Development  >  Understanding closures and decorators in python

Understanding closures and decorators in python

高洛峰
高洛峰Original
2017-03-03 13:58:011206browse

The closure in python is defined (interpreted) expressively as: If in an inner function, a variable in the outer scope (but not in the global scope) is referenced, then the inner function is considered closure.

The following instructions are mainly for python2.7, there may be differences in other versions.

Maybe it’s not easy to understand by looking at the definition directly. Let’s first look at what an internal function is:

def wai_hanshu(canshu_1):

  def nei_hanshu(canshu_2): # 我在函数内部有定义了一个函数
    return canshu_1*canshu_2

  return nei_hanshu  # 我将内部函数返回出去

a = wai_hanshu(123)   # 此时 canshu_1 = 123
print a
print a(321)  # canshu_2 = 321

Understanding closures and decorators in python

I have a function nested inside the function. When I pass a variable to the outer function and assign it to a, we find that a becomes a function object, and I again When this function object passes parameters, it also obtains the return value of the internal function. We know that according to the principle of scope, we cannot access the local scope in the global scope. However, the internal functions are accessed here through a tricky method. .

Let’s continue to look at an example:

def wai_hanshu():
  a = []
  def nei_hanshu(canshu):
    a.append(canshu)
    return a

  return nei_hanshu

a = wai_hanshu()
print a(123)
print a(321)

Understanding closures and decorators in python

It can be seen that the function is located in the external function List a has actually changed. To know why, you must first know what a Python namespace is, and namespaces are the reason for scope performance. Here I will briefly explain.

The main reason for introducing namespaces is to avoid variable conflicts, because there are many modules in python, and there are functions, classes, etc. in the modules, and they all use variables. But it would be too troublesome if you have to be careful not to conflict with other variable names every time. Developers should focus on their own problems, rather than thinking about what variables are used in programs written by others, so Python introduced namespaces. The namespace is divided into module layer, and the module is divided into global scope and local scope. If represented by a diagram:

Understanding closures and decorators in python

The namespaces between modules are different, and There are also global scopes and local scopes. Local scopes can also be nested before, so as to ensure that variable names do not conflict. By the way, I would like to add that the name of the namespace can be obtained through the __name__ attribute:

Understanding closures and decorators in python

The namespace of the main file is called '__main__', and the namespace of the module is the module name. .

The scope is born because when python is looking for a variable, it will first search in the current namespace. If it is not found in the current namespace, it will search in the upper-level namespace. By analogy, if it is not found in the end, an exception of variable not found will be triggered.

We have always said before: the global scope cannot access the local scope, but the local scope can access the global scope for this reason. And when I create a variable in the local scope with the same name as the outside, when python is looking for this variable, it will first look for it in the current scope. If it is found, it will not continue to look for it one level higher.

In early Python versions, local scopes could not access other local scopes, but could only access global ones. However, in current versions, they are searched one level up in order, so I will mention it here.

Because of this feature, we can access the variables in the external function in the internal function, which is the so-called closure.

Note: It is necessary to distinguish between objects here, for example:

def wai_hanshu():
  a = []
  def nei_hanshu(canshu):
    a.append(canshu)
    return a

  return nei_hanshu

a = wai_hanshu()  # 我创建了一个对象
b = wai_hanshu()  # 我又创建了一个对象
print a
print b
print a(123)
print b(321)

Understanding closures and decorators in python

Here , although we all operate variables in wai_hanshu, a and b are completely two objects, and the memory spaces where they are located are also different, so the data inside are also independent. Be careful not to mix things up.

Decorator

In fact, the decorator takes a few more steps based on the closure. Look at the code:

def zsq(func): # 装饰函数
  def nei():
    print '我在传入的函数执行之前做一些操作'
    func() # 执行函数
    print '我在目标函数执行后再做一些事情'
  return nei

def login():  # 被装饰函数
  print '我进行了登录功能'

login = zsq(login)  # 我将被装饰的函数传入装饰函数中,并覆盖了原函数的入口

login()   # 此时执行的就是被装饰后的函数了

Understanding closures and decorators in python

在看这段代码的时候,要知道几件事:

1.函数的参数传递的其实是引用,而不是值。

2.函数名也是一个变量,所以可以重新赋值。

3.赋值操作的时候,先执行等号右边的。

只有明白了上面这些事之后,再结合一下代码,应该就能明白什么是装饰器了。所谓装饰器就是在闭包的基础上传递了一个函数,然后覆盖原来函数的执行入口,以后调用这个函数的时候,就可以额外实现一些功能了。装饰器的存在主要是为了不修改原函数的代码,也不修改其他调用这个函数的代码,就能实现功能的拓展。

而python觉得让你每次都进行重命名操作实在太不方便,于是就给出了一个便利的写法:

def zsq(func):
  def nei():
    print '我在传入的函数执行之前做一些操作'
    func() # 执行函数
    print '我在目标函数执行后再做一些事情'
  return nei

@zsq  # 自动将其下面的函数作为参数传到装饰函数中去
def login():
  print '我进行了登录功能'


login()

Understanding closures and decorators in python

这些小便利也叫做python的语法糖,你可能在很多地方见过这个说法。

带参数的装饰器:

def zsq(a):
  print '我是装饰器的参数', a
  def nei(func):
    print '我在传入的函数执行之前做一些操作'
    func() # 执行函数
    print '我在目标函数执行后再做一些事情'
  return nei


@zsq('123')
def login():
  print '我进行了登录功能'

Understanding closures and decorators in python

相当于: login = zsq(123)(login) ,所以在这里没有调用就执行了。

装饰器的嵌套:

这里就不完整写个例子了:

@deco1(deco_arg) 
@deco2 
def func(): 
  pass

相当于: func = deco1(deco_arg)(deco2(func)) 

也就是从上到下的嵌套了。

关于闭包和装饰器就先讲到这里,以后有需要再补充。

以上这篇深入Understanding closures and decorators in python就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持PHP中文网。

更多Understanding closures and decorators in python相关文章请关注PHP中文网!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn