name = 'world' x = 3變量是代表某個值的名字
def hello(name): return 'hello' + name hello('Word) hello word函數通過def關鍵字、函數名和可選的參數列表定義。
是可以調用的,它執行某種行為并且返回一個值。
函數內部也可以定義函數
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 gglobal variable在函數內部遇到變量的時候會有現在自己的命名空間里找
猜一下段代碼會執行的結果是什么
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): ...: passIn [8]: AOut[8]: __main__.AIn [9]: type(A)Out[9]: typeIn [10]: def foo(): ....: passIn [11]: type(foo)Out[11]: function In [12]: A.__class__Out[12]: type In [13]: foo.__class__Out[13]: function In [14]: a = 1In [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)>> 3def make_adder(a): def adder(b): return b + a return adder add = make_adder(5)>> add# output<function adder at 0x108166140>>> add(3)# output8閉包可以認為是一個內層函數(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()# outputI am a stand alone function# 然后,我們在這里裝飾這個函數# 將函數傳遞給裝飾器,裝飾器將動態地將其包裝在任何想執行的代碼中,然后返回一個新的函數>> my_func = my_decorator(my_func)>> my_func()#outputBefore the function runsI am a stand alone functionAfter the function runs# 也可以這么寫@ my_decoratordef my_func(): print "I am a stand alone function" >> my_func()#outputBefore the function runsI am a stand alone functionAfter the function runs裝飾器可以嵌套使用
def bread(func): def wrapper(): print "</''''''/>" func() print "</______/>" return wrapperdef ingredients(func): def wrapper(): print "#tomatoes#" func() print "~salad~" return wrapperdef sandwich(food="--ham--"): print food#outputs:#嵌套兩個裝飾器>> sandwich = bread(ingredients(sandwich))>> sandwich()# outputs:</''''''/> #tomatoes# --ham-- ~salad~</______/>更簡單的寫法
@bread@ingredientsdef sandwich(food="--ham--"): print food裝飾器的順序是很重要的
@ingredients@breaddef sandwich(food="--ham--"): print food# outputs: #tomatoes# </' ' ' ' ' '/> --ham-- </______/> ~salad~首先看一下這段代碼
def deco(fn): print "I am %s!" % fn.__name__ @decodef func(): pass # outputI am func!# 沒有執行func 函數 但是 deco 被執行了@decoratordef 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()#outputBefore the function runsI am a stand alone functionAfter the function runsmy_decorator(my_func)返回了wrapper()函數,所以,my_func其實變成了wrapper的一個變量,而后面的my_func()執行其實變成了wrapper()
比如:多個decorator@decorator_one@decorator_twodef 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 wrapperclass 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)# outputx is -6b 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_decoratordef func(): pass func()#output****** args ******(){}@a_decoratordef func_with_args(a, b=0): pass return a + bfunc_with_args(1, b=2)#output****** args ******(1,){'b': 2}上邊的示例是帶參數的被裝飾函數
現在我們看一下向裝飾器本身傳遞參數
向裝飾器本身傳遞參數
再看一下這段代碼
def deco(fn): print "I am %s!" % fn.__name__ @decodef func(): pass # outputI am func!沒有執行func 函數 但是 deco 被執行了
其解釋器會解釋成下面這樣的語句:
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()#outputsI 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()# outputsI make decorators!As a decorator maker, I return a decoratorI 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_decodef 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')# outputsI make decorators! And I accept arguments: deco_arg1 deco_arg2As a decorator maker, I return a decoratorI am a decorator! Somehow you passed me arguments: deco_arg1 deco_arg2As 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 farg2I 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@bardef foo(): print "foo"print foo.__name__#outputs: wrapper"functools" 可以修正這個錯誤
import functoolsdef bar(func): # 我們所說的 "wrapper", 封裝 "func" @functools.wraps(func) def wrapper(): print "bar" return func() return wrapper@bardef foo(): print "foo"# 得到的是原始的名稱, 而不是封裝器的名稱print foo.__name__#outputs: fooclass myDecorator(object): def __init__(self, func): print "inside myDecorator.__init__()" self.func = func def __call__(self): self.func() print "inside myDecorator.__call__()" @myDecoratordef 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 wrapperfrom functools import wrapsdef 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 @memodef 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 decodef 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_fnPython本身提供了一些裝飾器:property,staticmethod
新聞熱點
疑難解答