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