下面这篇对装饰器讲的很好,懂了。

http://python.jobbole.com/85056/

《简单 12 步理解 Python 装饰器》

使用装饰器非常简单(见步骤10),但是写装饰器却很复杂。

2. 作用域

在 Python 函数中会创建一个新的作用域。Python 高手也称函数有自己的命名空间。也就是说,当在函数体中遇到变量时,Python 会首先在该函数的命名空间中寻找变量名。Python 有几个函数用来查看命名空间。下面来写一个简单函数来看看局部变量和全局变量的区别。

>>> a_string = "This is a global variable"
>>> def foo():
... print locals()
>>> print globals() # doctest: +ELLIPSIS
{..., 'a_string': 'This is a global variable'}
>>> foo() #
{}

内建函数 globals 返回一个包含所有 Python 能识别变量的字典。(为了更清楚的描述,输出时省略了 Python 自动创建的变量。)在注释 #2 处,调用了 foo 函数,在函数中打印局部变量的内容。从中可以看到,函数 foo 有自己单独的、此时为空的命名空间。

3. 变量解析规则

Python 的作用域规则是, 变量的创建总是会创建一个新的局部变量但是变量的访问(包括修改)在局部作用域查找然后是整个外层作用域来寻找匹配。

另一方面,如果尝试在函数里给全局变量赋值,结果并不是我们想要的那样:

>>> a_string = "This is a global variable"
>>> def foo():
... a_string = "test" #
... print locals()
>>> foo()
{'a_string': 'test'}
>>> a_string #
'This is a global variable'

注:要加上global关键字才行。

6. 内嵌函数

Python 允许创建内嵌函数。即可以在函数内部声明函数,并且所有的作用域和生命周期规则仍然适用。

>>> def outer():
... x =
... def inner():
... print x #
... inner() #
...
>>> outer()

7. 函数是 Python 中的一级对象

在 Python 中有个常识:函数和其他任何东西一样,都是对象。函数包含变量,它并不那么特殊。

这意味着可以将函数当做实参传递给函数,或者在函数中将函数作为返回值返回。如果你从未想过这样使用,请看下面的可执行代码:

 
>>> def add(x, y):
... return x + y
>>> def sub(x, y):
... return x - y
>>> def apply(func, x, y): #
... return func(x, y) #
>>> apply(add, , ) # >>> apply(sub, , )

但是,将函数作为值返回会怎样?思考下面代码:

>>> def outer():
... def inner():
... print "Inside inner"
... return inner #
...
>>> foo = outer() #
>>> foo # doctest:+ELLIPSIS
<function inner at 0x...>
>>> foo()
Inside inner

这看起来也许有点怪异。在 #1 处返回一个其实是函数标签的变量 inner。也没有什么特殊语法——函数 outer 返回了并没有被调用的函数 inner。还记得变量的生命周期吗?每次调用函数 outer 的时候,函数 inner 会被重新定义,但是如果函数 ouer 没有返回 inner,当 inner 超出 outer 的作用域,inner 的生命周期将结束。

在 #2 处将获得返回值即函数 inner,并赋值给新变量 foo。可以看到如果鉴定 foo,它确实包含函数 inner,通过使用调用操作符(双括号,还记得吗?)来调用它。虽然看起来可能有点怪异,但是目前为止并没有什么很难理解的,对吧?hold 住,因为接下来会更怪异!

8. 闭包

先不着急看闭包的定义,让我们从一段示例代码开始。如果将上一个示例稍微修改下:

>>> def outer():
... x =
... def inner():
... print x #
... return inner
>>> foo = outer()
>>> foo.func_closure # doctest: +ELLIPSIS
(<cell at 0x...: int object at 0x...>,)

foo()

1

返回的 inner 函数正常运行。Python 支持一种名为函数闭包的特性,意味着 在非全局作用域定义的 inner 函数在定义时记得外层命名空间是怎样的。inner 函数包含了外层作用域变量,通过查看它的 func_closure 属性可以看出这种函数闭包特性。

记住——每次调用函数 outer 时,函数 inner 都会被重新定义。此时 x 的值没有变化,所以返回的每个 inner 函数和其它的 inner 函数运行结果相同,但是如果稍做一点修改呢?

>>> def outer(x):
... def inner():
... print x #
... return inner
>>> print1 = outer()
>>> print2 = outer()
>>> print1() >>> print2()

闭包是强大的技术——在某些方面来看可能感觉它有点像面向对象技术:outer 作为 inner的构造函数,有一个类似私有变量的 x。闭包的作用不胜枚举——如果你熟悉 Python中 sorted 函数的参数 key,也许你已经写过 lambda 函数通过第二项而非第一项来排序一些列表。也可以写一个 itemgetter 函数,接收一个用于检索的索引并返回一个函数,然后就能恰当的传递给 key 参数了。

找到了一个示例,如下:

a = [,,]
>>> b=operator.itemgetter() //定义函数b,获取对象的第1个域的值
>>> b(a) >>> b=operator.itemgetter(,) //定义函数b,获取对象的第1个域和第0个的值
>>> b(a)
(, ) 要注意,operator.itemgetter函数获取的不是值,而是定义了一个函数,通过该函数作用到对象上才能获取值。 sorted函数用来排序,sorted(iterable[, cmp[, key[, reverse]]]) 其中key的参数为一个函数或者lambda函数。所以itemgetter可以用来当key的参数 a = [('john', 'A', ), ('jane', 'B', ), ('dave', 'B', )] 根据第二个域和第三个域进行排序 sorted(students, key=operator.itemgetter(,))

但是这么用闭包太没意思了!让我们再次从头开始,写一个装饰器。

9. 装饰器

装饰器其实就是一个以函数作为参数并返回一个替换函数的可执行函数。

>>> def outer(some_func):
... def inner():
... print "before some_func"
... ret = some_func() #
... return ret +
... return inner
>>> def foo():
... return
>>> decorated = outer(foo) #
>>> decorated()
before some_func

下面的Wrapper就是装饰器:

>>> def wrapper(func):
... def checker(a, b): #
... if a.x < or a.y < :
... a = Coordinate(a.x if a.x > else , a.y if a.y > else )
... if b.x < or b.y < :
... b = Coordinate(b.x if b.x > else , b.y if b.y > else )
... ret = func(a, b)
... if ret.x < or ret.y < :
... ret = Coordinate(ret.x if ret.x > else , ret.y if ret.y > else )
... return ret
... return checker
>>> add = wrapper(add)
>>> sub = wrapper(sub)
>>> sub(one, two)
Coord: {'y': , 'x': }
>>> add(one, three)
Coord: {'y': , 'x': }

10. 函数装饰器 @ 符号的应用

Python 2.4 通过在函数定义前添加一个装饰器名和 @ 符号,来实现对函数的包装。在上面代码示例中,用了一个包装的函数来替换包含函数的变量来实现了装饰函数。

>>> @ wrapper
... def add(a, b):
... return Coordinate(a.x + b.x, a.y + b.y)

相当于:

>>> add = wrapper(add)

11. args 和 *kwargs

>>> def one(*args):
... print args #
>>> one()
()
>>> one(, , )
(, , )
>>> def two(x, y, *args): #
... print x, y, args
>>> two('a', 'b', 'c')
a b ('c',)

也可以像下面这样传参:

>>> def add(x, y):
... return x + y
>>> lst = [,]
>>> add(lst[], lst[]) # >>> add(*lst) #

对于 **

>>> def foo(**kwargs):
... print kwargs
>>> foo()
{}
>>> foo(x=, y=)
{'y': , 'x': }
>>> dct = {'x': , 'y': }
>>> def bar(x, y):
... return x + y
>>> bar(**dct)

12. 更通用的装饰器

用学到的新知识,可以写一个记录函数参数的装饰器。为简单起见,仅打印到标准输出:

>>> def logger(func):
... def inner(*args, **kwargs): #
... print "Arguments were: %s, %s" % (args, kwargs)
... return func(*args, **kwargs) #
... return inner

注意在 #1 处函数 inner 接收任意数量和任意类型的参数,然后在 #2 处将他们传递给被包装的函数。这样一来我们可以包装或装饰任意函数,而不用管它的签名。

>>> @logger
... def foo1(x, y=):
... return x * y
>>> @logger
... def foo2():
... return
>>> foo1(, )
Arguments were: (, ), {} >>> foo1()
Arguments were: (,), {} >>> foo2()
Arguments were: (), {}

每一个函数的调用会有一行日志输出和预期的返回值。

再聊装饰器

如果你一直看到了最后一个实例,祝贺你,你已经理解了装饰器!你可以用新掌握的知识做更多的事了。

你也许考虑需要进一步的学习:Bruce Eckel 有一篇很赞的关于装饰器文章,他使用了对象而非函数来实现了装饰器。你会发现 OOP 代码比纯函数版的可读性更好。Bruce 还有一篇后续文章 providing arguments to decorators,用对象实现装饰器也许比用函数实现更简单。最后,你可以去研究一下内建包装函数 functools,它是一个在装饰器中用来修改替换函数签名的装饰器,使得这些函数更像是被装饰的函数。

functools,用于高阶函数:指那些作用于函数或者返回其它函数的函数,通常只要是可以被当做函数调用的对象就是这个模块的目标。

下次再看哈。

Python学习-修饰器 - itemgetter的妙用的更多相关文章

  1. Python学习---装饰器/迭代器/生成器的学习【all】

    Python学习---装饰器的学习1210 Python学习---生成器的学习1210 Python学习---迭代器学习1210

  2. python中用修饰器进行异常日志记录

    当脚本中需要进行的的相同的异常操作很多的时候,可以用修饰器来简化代码.比如我需要记录抛出的异常: 在log_exception.py文件中, import functools import loggi ...

  3. python函数修饰器(decorator)

    python语言本身具有丰富的功能和表达语法,其中修饰器是一个非常有用的功能.在设计模式中,decorator能够在无需直接使用子类的方式来动态地修正一个函数,类或者类的方法的功能.当你希望在不修改函 ...

  4. Python学习---装饰器的学习1210

    装饰器的基础 学习前提: 作用域 + 函数的理解 + 闭包  [学习,理解] 代码编写原则: 对修改开放对扩展开放 装饰器本质上是一个函数,该函数用来处理其他函数,它可以让其他函数在不需要修改代码的前 ...

  5. python 类修饰器

    1. 修改类函数. 场景: 如果要给一个类的所有方法加上计时,并打印出来.demo如下: # -*- coding:utf-8 -*- import time def time_it(fn): &qu ...

  6. python decorator 修饰器

    decorator 就是给函数加一层皮,好用! 1 from time import ctime 2 3 def deco(func): 4 def wrappedFunc(*args, **kwar ...

  7. Python 函数修饰器

    # 一.用函数修饰函数 #!/usr/bin/python3 def decorate_func(func): def call(*args, **kwargs): print('you have c ...

  8. python学习---装饰器

    什么是装饰器 器即函数 装饰即修饰,意指为其他函数添加新功能 装饰器定义:本质就是函数,功能是为其他函数添加新功能 装饰器需要遵循的原则 1.不修改被装饰函数的源代码(开放封闭原则) 2.为被装饰函数 ...

  9. python学习——装饰器函数

    一.装饰器函数的作用是什么 答:装饰器函数是在不修改原函数及其调用方式的情况下对原函数功能进行扩展 对于搞python开发的人来说,函数占据了至关重要的地位.都说学好函数你就可以去找工作了,好了,假如 ...

随机推荐

  1. 麦森数--NOIP2003

    题目描述 形如2P−12^{P}-12P−1 的素数称为麦森数,这时PPP 一定也是个素数.但反过来不一定,即如果PPP 是个素数,2P−12^{P}-12P−1 不一定也是素数.到1998年底,人们 ...

  2. awk查找特定字段

    在一行中,查找字段包含exe的: ###########awk.awk######## { for(i=1;i<NF;i++) { if($i ~ /exe/) { print $i } } } ...

  3. Spark深入之RDD

    目录 Part III. Low-Level APIs Resilient Distributed Datasets (RDDs) 1.介绍 2.RDD代码 3.KV RDD 4.RDD Join A ...

  4. 洛谷P2916 [USACO08NOV]为母牛欢呼(最小生成树)

    P2916 [USACO08NOV]为母牛欢呼Cheering up the C… 题目描述 Farmer John has grown so lazy that he no longer wants ...

  5. POJ 1753 DFS

    思路: 有过两个裸搜的思路,第一个一个无限TLE,第二个还不慢... 错误思路:迭代加深搜索,枚举翻第几个棋,挂的原因:16的16次方,不挂就怪了. 错误代码见下: #include <cstd ...

  6. three.js 流程图

    用Axure做了个模型图:          第一步: Scene --模型.灯光.特效 第二步: Camera --视角 第三步: Renderer -- 渲染输出 第四步: render --渲染 ...

  7. Java_Web之俱乐部会员信息管理系统

    使用 Jsp实现俱乐部会员信息管理功能,orac1e11g作为后台数据库,该系统包括查看俱乐部会员信息列表和修改俱乐部会员信息两人功能,具体耍求如下: 打开俱乐部会员信息列表页面,以列表方式显示所有俱 ...

  8. MySQL基础配置之mysql的默认字符编码的设置(my.ini设置字符编码)

    MySQL基础配置之mysql的默认字符编码的设置(my.ini设置字符编码) MySQL的默认编码是Latin1,不支持中文,那么如何修改MySQL的默认编码呢,下面以设置UTF-8为例来说明. 需 ...

  9. python排序sorted与sort比较 (转)

    Python list内置sort()方法用来排序,也可以用python内置的全局sorted()方法来对可迭代的序列排序生成新的序列. sorted(iterable,key=None,revers ...

  10. 小程序text组件内部上边距的问题

    index.wxml: <view class="slogan"> <text> 建立跨文化的全球视野,做世界公民 </text> </v ...