name = 'world' x = 3
变量是表明某个值的名字python
def hello(name): return 'hello' + name hello('word) hello word
函数经过def关键字、函数名和可选的参数列表定义。git
是能够调用的,它执行某种行为而且返回一个值。设计模式
函数内部也能够定义函数数组
def outer(): x = 1 def inner(): print x # 1 inner() >> outer() 1
def func(x): print 'x is', x print locals() func(50) >> x is 50 {'x': 50} >> print x Traceback (most recent call last): NameError: name 'x' is not defined
函数会建立一个新的做用域(命名空间)。缓存
函数的命名空间随着函数调用开始而开始,结束而销毁闭包
g = 'global variable' >> print globals() {'g': 'global variable', '__builtins__': <module '__builtin__' (built-in)>, '__file__': 'test.py', '__package__': None, 'func': <function func at 0x10472d8c0>, '__name__': '__main__', '__doc__': None} def foo(): g = 'test' print 'g is', g print locals() print globals() >> foo() g is test {'g': 'test'} {'g': 'global variable', '__builtins__': <module '__builtin__' (built-in)>, '__file__': 'test.py', '__package__': None, 'func': <function func at 0x10472d8c0>, '__name__': '__main__', '__doc__': None} >> print g global variable
在函数内部遇到变量的时候会有如今本身的命名空间里找app
猜一下段代码会执行的结果是什么ide
g = '我已经定义了' def foo(): print g g = '我从新定义了' print g
答案函数
函数有两种参数性能
def foo(x, y=0): return x - y
*args and **kwargs? [duplicate]
函数和python中其余同样都是对象
In [7]: class A(object): ...: pass In [8]: A Out[8]: __main__.A In [9]: type(A) Out[9]: type In [10]: def foo(): ....: pass In [11]: type(foo) Out[11]: function In [12]: A.__class__ Out[12]: type In [13]: foo.__class__ Out[13]: function In [14]: a = 1 In [15]: a.__class__ Out[15]: int # 类 是对象 In [16]: issubclass(A.__class__, object) Out[16]: True # 变量 是对象 In [17]: issubclass(a.__class__, object) Out[17]: True # 函数 是对象 In [18]: issubclass(foo.__class__, object) Out[18]: True
因此函数也能够做为参数传递给其它函数,也能够被当作返回值返回
def add(x, y): return x + y def apply(func): return func >> a = apply(add) >> type(a) <type 'function'> >> a(1, 2) >> 3
def make_adder(a): def adder(b): return b + a return adder add = make_adder(5) >> add # output <function adder at 0x108166140> >> add(3) # output 8
闭包能够认为是一个内层函数(adder),由一个变量指代,而这个变量相对于外层包含它的函数而言,是本地变量
嵌套定义在非全局做用域里面的函数可以记住它在被定义的时候它所处的封闭命名空间
闭包只是在形式和表现上像函数,但实际上不是函数。函数是一些可执行的代码,这些代码在函数被定义后就肯定了,不会在执行时发生变化,因此一个函数只有一个实例。闭包在运行时能够有多个实例,不一样的引用环境和相同的函数组合能够产生不一样的实例。
对一个已有的模块作一些“修饰工做”,所谓修饰工做就是想给现有的模块加上一些小装饰(一些小功能,这些小功能可能好多模块都会用到),但又不让这个小装饰(小功能)侵入到原有的模块中的代码里去
def my_decorator(func): def wrapper(): print "Before the function runs" func() print "After the function runs" return wrapper def my_func(): print "I am a stand alone function" >> my_func() # output I am a stand alone function # 而后,咱们在这里装饰这个函数 # 将函数传递给装饰器,装饰器将动态地将其包装在任何想执行的代码中,而后返回一个新的函数 >> my_func = my_decorator(my_func) >> my_func() #output Before the function runs I am a stand alone function After the function runs # 也能够这么写 @ my_decorator def my_func(): print "I am a stand alone function" >> my_func() #output Before the function runs I am a stand alone function After the function runs
装饰器能够嵌套使用
def bread(func): def wrapper(): print "</''''''\>" func() print "<\______/>" return wrapper def ingredients(func): def wrapper(): print "#tomatoes#" func() print "~salad~" return wrapper def sandwich(food="--ham--"): print food #outputs: #嵌套两个装饰器 >> sandwich = bread(ingredients(sandwich)) >> sandwich() # outputs: </''''''\> #tomatoes# --ham-- ~salad~ <\______/>
更简单的写法
@bread @ingredients def sandwich(food="--ham--"): print food
装饰器的顺序是很重要的
@ingredients @bread def sandwich(food="--ham--"): print food # outputs: #tomatoes# </' ' ' ' ' '\> --ham-- <\______/> ~salad~
首先看一下这段代码
def deco(fn): print "I am %s!" % fn.__name__ @deco def func(): pass # output I am func! # 没有执行func 函数 可是 deco 被执行了
@decorator def func(): pass
其解释器会解释成下面这样的语句:
func = decorator(func)
其实就是把一个函数当参数传到另外一个函数中,而后再回调
可是值得注意的是装饰器必须返回一个函数给func
回到刚才的例子
def my_decorator(func): def wrapper(): print "Before the function runs" func() print "After the function runs" return wrapper def my_func(): print "I am a stand alone function" >> my_func = my_decorator(my_func) >> my_func() #output Before the function runs I am a stand alone function After the function runs
my_decorator(my_func)返回了wrapper()函数,因此,my_func其实变成了wrapper的一个变量,然后面的my_func()执行其实变成了wrapper()
好比:多个decorator @decorator_one @decorator_two def func(): pass 至关于: func = decorator_one(decorator_two(func)) 好比:带参数的decorator: @decorator(arg1, arg2) def func(): pass 至关于: func = decorator(arg1,arg2)(func)
首先看一下, 若是被装饰的方法有参数
def a_decorator(method_to_decorate): def wrapper(self, x): x -= 3 print 'x is %s' % x method_to_decorate(self, x) return wrapper class A(object): def __init__(self): self.b = 42 @a_decorator def number(self, x): print "b is %s" % (self.b + x) a = A() a.number(-3) # output x is -6 b is 36
一般咱们都使用更加通用的装饰器,能够做用在任何函数或对象方法上,而没必要关系其参数 使用
def a_decorator(method_to_decorate): def wrapper(*args, **kwargs): print '****** args ******' print args print kwargs method_to_decorate(*args, **kwargs) return wrapper @a_decorator def func(): pass func() #output ****** args ****** () {} @a_decorator def func_with_args(a, b=0): pass return a + b func_with_args(1, b=2) #output ****** args ****** (1,) {'b': 2}
上边的示例是带参数的被装饰函数
如今咱们看一下向装饰器自己传递参数
向装饰器自己传递参数
再看一下这段代码
def deco(fn): print "I am %s!" % fn.__name__ @deco def func(): pass # output I am func!
没有执行func 函数 可是 deco 被执行了
在用某个@deco来修饰某个函数func时
其解释器会解释成下面这样的语句:
func = deco(func)
装饰器必须使用函数做为参数,你不能直接传递参数给装饰器自己
若是想传递参数给装饰器,能够 声明一个用于建立装饰器的函数
# 我是一个建立装饰器的函数 def decorator_maker(): print "I make decorators!" def my_decorator(func): print "I am a decorator!" def wrapped(): print "I am the wrapper around the decorated function. " return func() print "As the decorator, I return the wrapped function." return wrapped print "As a decorator maker, I return a decorator" return my_decorator # decorator_maker()返回的是一个装饰器 new_deco = decorator_maker() #outputs I make decorators! As a decorator maker, I return a decorator # 使用装饰器 def decorated_function(): print "I am the decorated function" decorated_function = new_deco(decorated_function) decorated_function() # outputs I make decorators! As a decorator maker, I return a decorator I am a decorator! As the decorator, I return the wrapped function. I am the wrapper around the decorated function. I am the decorated function
decorated_function = new_deco(decorated_function) # 等价于下面的方法 @new_deco def func(): print "I am the decorated function" @decorator_maker() def func(): print "I am the decorated function"
my_decorator(装饰器函数)是decorator_maker(装饰器生成函数)的内部函数
因此可使用把参数加在decorator_maker(装饰器生成函数)的方法像装饰器传递参数
# 我是一个建立带参数装饰器的函数 def decorator_maker_with_arguments(darg1, darg2): print "I make decorators! And I accept arguments:", darg1, darg2 def my_decorator(func): print "I am a decorator! Somehow you passed me arguments:", darg1, darg2 def wrapped(farg1, farg2): print "I am the wrapper around the decorated function." print "I can access all the variables", darg1, darg2, farg1, farg2 return func(farg1, farg2) print "As the decorator, I return the wrapped function." return wrapped print "As a decorator maker, I return a decorator" return my_decorator @decorator_maker_with_arguments("deco_arg1", "deco_arg2") def decorated_function_with_arguments(function_arg1, function_arg2): print ("I am the decorated function and only knows about my arguments: {0}" " {1}".format(function_arg1, function_arg2)) decorated_function_with_arguments('farg1', 'farg2') # outputs I make decorators! And I accept arguments: deco_arg1 deco_arg2 As a decorator maker, I return a decorator I am a decorator! Somehow you passed me arguments: deco_arg1 deco_arg2 As the decorator, I return the wrapped function. I am the wrapper around the decorated function. I can access all the variables deco_arg1 deco_arg2 farg1 farg2 I am the decorated function and only knows about my arguments: farg1 farg2
这里装饰器生成函数内部传递参数是闭包的特性
最后Python2.5解决了最后一个问题,它提供functools模块,包含functools.wraps.这个函数会将被装饰函数的名称,模块,文档字符串拷贝给封装函数
def foo(): print "foo" print foo.__name__ #outputs: foo # 但当你使用装饰器 def bar(func): def wrapper(): print "bar" return func() return wrapper @bar def foo(): print "foo" print foo.__name__ #outputs: wrapper
"functools" 能够修正这个错误
import functools def bar(func): # 咱们所说的 "wrapper", 封装 "func" @functools.wraps(func) def wrapper(): print "bar" return func() return wrapper @bar def foo(): print "foo" # 获得的是原始的名称, 而不是封装器的名称 print foo.__name__ #outputs: foo
class myDecorator(object): def __init__(self, func): print "inside myDecorator.__init__()" self.func = func def __call__(self): self.func() print "inside myDecorator.__call__()" @myDecorator def aFunction(): print "inside aFunction()" print "Finished decorating aFunction()" aFunction() # output: # inside myDecorator.__init__() # Finished decorating aFunction() # inside aFunction() # inside myDecorator.__call__()
咱们能够看到这个类中有两个成员:
**若是decorator有参数的话,init() 就不能传入func了,而fn是在__call__的时候传入**
class myDecorator(object): def __init__(self, arg1, arg2): self.arg1 = arg2 def __call__(self, func): def wrapped(*args, **kwargs): return self.func(*args, **kwargs) return wrapped
def counter(func): """ 记录并打印一个函数的执行次数 """ def wrapper(*args, **kwargs): wrapper.count = wrapper.count + 1 res = func(*args, **kwargs) print "{0} has been used: {1}x".format(func.__name__, wrapper.count) return res wrapper.count = 0 return wrapper
from functools import wraps def memo(fn): cache = {} miss = object() @wraps(fn) def wrapper(*args): result = cache.get(args, miss) if result is miss: result = fn(*args) print "{0} has been used: {1}x".format(fn.__name__, wrapper.count) cache[args] = result return result return wrapper @memo def fib(n): if n < 2: return n return fib(n - 1) + fib(n - 2)
15言和知性中用到的缓存
def cache_for(duration): def deco(func): @wraps(func) def fn(*args, **kwargs): key = pickle.dumps((args, kwargs)) value, expire = func.func_dict.get(key, (None, None)) now = int(time.time()) if value is not None and expire > now: return value value = func(*args, **kwargs) func.func_dict[key] = (value, int(time.time()) + duration) return value return fn return deco
def timeit(fn): @wraps(fn) def real_fn(*args, **kwargs): if config.common['ENVIRON'] == 'PRODUCTION': return fn(*args, **kwargs) _start = time.time() #app.logger.debug('Start timeit for %s' % fn.__name__) result = fn(*args, **kwargs) _end = time.time() _last = _end - _start app.logger.debug('End timeit for %s in %s seconds.' % (fn.__name__, _last)) return result return real_fn