对python新手而言,要理解闭包、装饰器,就要先懂下面这些东东!
先来看下一个函数接受另外一个函数以及一个数字当作参数,并且重复调用指定函数指定次数
cat test.py
def hello(): # hello函数
print("hello")
def repeat(fn,times): # 函数名是函数的入口地址
for i in range(times):
fn()
repeat(hello,3)
python test.py # 执行结果
hello
hello
hello
函数也可以在其它函数内部声明
cat test.py
def print_integer(values):
def is_integer(value):
try:
return value == int(value)
except:
return False
for v in values:
if is_integer(v):
print(v)
python test.py # 执行结果
1
2
3
# 相比函数当作参数传递,我们可以将它包装在另外的函数中,从而向函数增加新的行为。
# 向函数增加跟踪输出,有助于我们理解
def hello():
print("hello")
def repeat(fn,times):
for i in range(times):
fn()
def print_call(fn):
def fn_wrap(*args, **kwargs): #take any arguments
print ("Calling %s" % (fn.func_name))
return fn(*args, **kwargs) #pass any arguments to fn()
return fn_wrap
test = print_call(hello)
print "Returning func name: %s" % test.func_name
repeat(test,2)
python test.py # 执行结果
Returning func name: fn_wrap # 函数改变了
Calling hello
hello
Calling hello
hello
# 如果想包装一个函数同时保留它原来的函数名,可以这样实现
def print_call(fn):
def fn_wrap(*args, **kwargs): #take any arguments
print ("Calling %s" % (fn.func_name))
return fn(*args, **kwargs) #pass any arguments to fn()
fn_wrap.func_name = fn.func_name # 原来的函数名赋值给返回的函数名
return fn_wrap
python test.py # 执行结果
Returning func name: hello # 函数名保持一致
Calling hello
hello
Calling hello
hello
# 下面该讲闭包了,闭包的定义有很多,简单点说就是:一个可以引用在函数闭合范围内变量的函数
a = 3
def get_a():
return a
print get_a()
python test.py # 执行结果
3
a = 3
def get_a():
return a
def set_a(val):
a = val
set_a(5)
print get_a()
python test.py # 执行结果还是3
3
# 这里闭包不能写入任何被捕获的变量,a = val实际上写入了本地变量a,隐藏了全局的a。为了解决这种限制,可以用一个容器类型
class A(object):
pass
a = A()
a.value = 3
def get_a():
return a.value
def set_a(val):
global a
a.value = val
set_a(5)
print get_a()
python test.py # 执行结果
5
# 我们知道函数从它的闭合范围捕获变量,现在我们可以学习偏函数(prtial)了
# 一个偏函数是一个填充了部分或全部参数的函数的实例,很多时候偏函数可以消除代码的重复
# 偏函数默认pythhn库已经封装好了,只需要from functools import partial即可
def get_stuff(user,pw,stuff_id):
print("user: %s,pw: %s,stuff_id: %s" % (user,pw,stuff_id))
def partial(fn,*args,**kwargs):
def fn_part(*fn_args,**fn_kwargs): # *可以传参tuple, **可以传参dict
kwargs.update(fn_kwargs)
return fn(*args + fn_args, **kwargs)
return fn_part
my_stuff = partial(get_stuff,'user','pass')
my_stuff(5)
python test2.py # 执行结果
user: user,pw: pass,stuff_id: 5
# 最后我们来看看函数装饰器,函数装饰器接受一个函数作为参数然后返回一个新的函数。
# 装饰器本质是:改变了函数的代码入口点
# 装饰器就是一个函数,这个函数可以是内置的(@staticmethod、@classmethod),也可以是自定义的函数。
def print_call(fn):
def fn_wrap(*args, **kwargs): #take any arguments
print ("Calling %s" % (fn.func_name))
return fn(*args, **kwargs) #pass any arguments to fn()
fn_wrap.func_name = fn.func_name
return fn_wrap
@print_call # 使用@符号标记,挺方便的!
def will_be_logged(arg):
return arg*5
print will_be_logged('#')
python test.py # 执行结果
Calling will_be_logged
#####
# 内置修饰符
# @staticmethod vs @classmethod
# @staticmethod不需要表示自身对象的self和自身类的cls参数,就跟使用函数一样,只能直接类名.属性名或类名.方法名。
# @classmethod也不需要self参数,但第一个参数需要是表示自身类的cls参数,有cls参数,可以来调用类的属性,类的方法,实例化对象。
# @property 对类属性的操作,类似于java中定义getter/setter
class A(object):
bar = 1
def foo(self):
print 'foo'
@staticmethod
def static_foo():
print 'static_foo'
print A.bar
@classmethod
def class_foo(cls):
print 'class_foo'
print cls.bar
cls().foo()
A.static_foo()
A.class_foo()
输出结果:
static_foo
1
class_foo
1
foo
# @property 对类属性的操作,类似于java中定义getter/setter
class B():
def __init__(self):
self.__prop = 1
@property
def prop(self):
print "call get"
return self.__prop
@prop.setter
def prop(self, value):
print "call set"
self.__prop = value
@prop.deleter
def prop(self):
print "call del"
del self.__prop
# @引用多个函数装饰器
def makebold(fn):
def wrapped():
return "<b>" + fn() + "</b>"
return wrappeddef
def makeitalic(fn):
def wrapped():
return "<i>" + fn() + "</i>"
return wrapped
@makebold
@makeitalic
def hello():
return "hello world"
print hello() # 执行结果如下
<b><i>hello world</i></b>
# 给装饰器传参
def require(role):
def wrapper(fn):
def new_fn(*args, **kwargs):
if not role in kwargs.get('roles', []):
print("%s not in %s" % (role, kwargs.get('roles', [])))
raise Exception("Unauthorized")
return fn(*args, **kwargs)
return new_fn
return wrapper
@require('admin')
def get_users(**kwargs):
return ('Alice', 'Bob')
print get_users(roles=['user','admin'])
python test.py # 执行结果
('Alice', 'Bob')
# 函数装饰器就是这样了!未来可能有类装饰器。
扩展
decorator模块
decorator模块是 Michele Simionato 为简化python的decorator的使用难度而开发的, 使用它,你可以更加容易的使用decorator机制写出可读性、可维护性更好的代码
参考链接
http://book42qu.readthedocs.org/en/latest/python/python-closures-and-decorators.html
http://blog.csdn.net/terry_tusiki/article/details/14223649
http://blog.csdn.net/handsomekang/article/details/9615239
http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/001386820062641f3bcc60a4b164f8d91df476445697b9e000(@property sample)
转载于:https://blog.51cto.com/iceyao/1602047