VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > Python基础教程 >
  • 一步步教你理解Python装饰器

或许你已经用过装饰器,它的使用方式非常简单但理解起来困难(其实真正理解的也很简单),想要理解装饰器,你需要懂点函数式编程的概念,python函数的定义以及函数调用的语法规则等,虽然我没法把装饰器变得简单,但是我希望可以通过下面的步骤让你由浅入深明白装饰器是什么。假定你拥有最基本的Python知识,本文阐述的东西可能对那些在工作中经常接触Python的人有很大的帮助。下面我们来一步步理解python的装饰器:

1、函数(Functions)

在Python里,函数是用def关键字后跟一个函数名称和一个可选的参数表列来创建的,可以用关键字return指定返回值。下面让我们创建和调用一个最简单的函数:

1
2
3
4
>>> def foo():
...     return 1
>>> foo()
1

该函数的函数体(在Python里将就是多行语句)是强制性的并且通过缩进来表明。我们可以通过在函数名后面添加双括号来调用函数。

 

2、作用域(Scope)

在Python中,每个函数都会创建一个作用域。Pythonistas也可能称函数拥有它们自己的命名空间(namespace)。这意味着当在函数体里遇到变量名时,Python首先在该函数的命名空间中查找,Python包含了一些让我们查看命名空间的函数。让我们写一个简单的函数来探查一下local和global作用域的区别。

1
2
3
4
5
6
7
>>> a_string = "This is a global variable"
>>> def foo():
...     print locals()
>>> print globals() # doctest: +ELLIPSIS
{..., 'a_strin''This ia a global variable'}
>>> foo() # 2
{}

内建的globals函数返回一个字典对象,它包含所有Python知道的变量名(为了清楚明了起见,我已经忽略了一些Python自动创建的变量)。在#2处我调用了函数foo,它将函数内部的local namespace里的内容打印了出来。正如我们看到的foo函数拥有自己的独立namespace,现在它还是空的。

 

3、变量解析规则(variable resolution rules)

当然,这并不意味着在函数内部我们不能访问全局变量。Python的作用域规则是,变量的创建总会创建一个新的local变量,但是变量的访问(包括修改)会先查找local作用域然后顺着最邻近的作用域去寻找匹配。因此,如果我们修改foo函数来让它打印global变量,结果就会像我们希望的那样:

1
2
3
4
5
>>> a_string = "This is global variable"
>>> def foo():
...     print a_string # 1
>>> foo()
This is a global variable

在#1处,Python在函数中寻找一个local变量,但是没有找到,然后在global变量中找到了一个同名的变量。

 

另一方面,如果我们尝试在函数里给global变量赋值,结果将不如我们所愿:

1
2
3
4
5
6
7
8
>>> a_string = 'This is a global variable"
>>> def foo():
...     a_string = "test" # 1
...        print locals()
>>> foo()
{'a_string''test'}
>>> a_string # 2
'This is a global variable'

正如我们所见,全局变量可以被访问到(如果是可变类型,其甚至可以被改变),但是(默认情况下)不能被赋值。在函数内部的#1处我们实际上创建了一个新的local变量,它和全局变量拥有相同的名字,它将全局变量给覆盖了。我们可以通过在foo函数内部打印local namespace来发现到它已经有了一个条目,通过对函数外部的#2处的输出结果我们可以看到,变量a_string的值根本就没有被改变。

 

4、变量的生命周期(Variable lifetime)

也要注意到,变量不仅“生活在”一个命名空间里,它们还有生命周期。考虑下面的代码:

1
2
3
4
5
6
7
>>> def foo():
...     x = 1
>>> foo()
>>> print x # 1
Traceback (most recent call last):
...
NameError: name 'x' is not defined

相关教程