理解 Python 中的装饰器
- Python
- 2017-09-28
- 194热度
- 1评论
导航
一直觉得装饰器很神奇。如 Flask 中用到的路由装饰器:
@app.route('/')
def hello_world():
return 'Hello World!
看了《简单 12 步理解 Python 装饰器》,有些心得,记录一下新知识。
1、内嵌函数
Python 允许创建内嵌函数。即可以在函数内部声明函数,并且所有的作用域和生命周期规则仍然适用。
>>> def outer():
... x = 1
... def inner():
... print x # 1
... inner() # 2
...
>>> outer()
1
2、函数也是对象
function 是 object 的子类,可以作为参数传递
>>> def add(x, y):
... return x + y
>>> def sub(x, y):
... return x - y
>>> def apply(func, x, y): # 1
... return func(x, y) # 2
>>> apply(add, 2, 1) # 3
3
>>> apply(sub, 2, 1)
1
3、闭包
打破了作用域规则。即使外层函数被销毁,内层函数也可以记住外层作用域。
>>> def outer(x):
... def inner():
... print x # 1
... return inner
>>> print1 = outer(1)
>>> print2 = outer(2)
>>> print1()
1
>>> print2()
2
4、装饰器
利用内嵌函数机制,对函数进行包装,添加额外功能
>>> class Coordinate(object):
... def __init__(self, x, y):
... self.x = x
... self.y = y
... def __repr__(self):
... return "Coord: " + str(self.__dict__)
>>> def add(a, b):
... return Coordinate(a.x + b.x, a.y + b.y)
>>> def sub(a, b):
... return Coordinate(a.x - b.x, a.y - b.y)
>>> one = Coordinate(100, 200)
>>> two = Coordinate(300, 200)
>>> three = Coordinate(-100, -100)
>>> def wrapper(func):
... def checker(a, b): # 1
... if a.x < 0 or a.y < 0:
... a = Coordinate(a.x if a.x > 0 else 0, a.y if a.y > 0 else 0)
... if b.x < 0 or b.y < 0:
... b = Coordinate(b.x if b.x > 0 else 0, b.y if b.y > 0 else 0)
... ret = func(a, b)
... if ret.x < 0 or ret.y < 0:
... ret = Coordinate(ret.x if ret.x > 0 else 0, ret.y if ret.y > 0 else 0)
... return ret
... return checker
>>> add = wrapper(add)
>>> sub = wrapper(sub)
>>> sub(one, two)
Coord: {'y': 0, 'x': 0}
>>> add(one, three)
Coord: {'y': 200, 'x': 100}
5、装饰器语法糖
Python 2.4 通过在函数定义前添加一个装饰器名和 @ 符号,来实现对函数的包装。
>>> @ wrapper
... def add(a, b):
... return Coordinate(a.x + b.x, a.y + b.y)
6、用可变参数实现更通用的装饰器
>>> def logger(func):
... def inner(*args, **kwargs): #1
... print "Arguments were: %s, %s" % (args, kwargs)
... return func(*args, **kwargs) #2
... return inner
>>> @logger
... def foo1(x, y=1):
... return x * y
>>> @logger
... def foo2():
... return 2
>>> foo1(5, 4)
Arguments were: (5, 4), {}
20
>>> foo1(1)
Arguments were: (1,), {}
1
>>> foo2()
Arguments were: (), {}
2
建议加上 functools.wrap 注解
https://blog.csdn.net/hqzxsc2006/article/details/50337865