国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

理解python裝飾器

2019-11-14 16:58:15
字體:
來源:轉載
供稿:網友

變量

    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

答案

函數參數

函數有兩種參數

  1. 位置參數
  2. 命名參數
	def foo(x, y=0):		return x - y

*args and **kwargs? [duplicate]

python 中一切都是對象

函數和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)>> 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)# output8
  • adder 就是一個閉包
  • 也可以說 make_adder 指向一個閉包
  • 或者說 make_add 是閉包的工廠函數

閉包可以認為是一個內層函數(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

裝飾器是設計模式中裝飾器模式英文版)的python實現

多個裝飾器

裝飾器可以嵌套使用

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~

Decorator 的本質

首先看一下這段代碼

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 runs

my_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.4的新特性
  • 裝飾器會降低代碼的性能
  • 裝飾器僅在Python代碼導入時被調用一次,之后你不能動態地改變參數.當你使用"import x",函數已經被裝飾

最后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: foo

類裝飾器

class 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__()

我們可以看到這個類中有兩個成員:

  1. 一個是__init__(),這個方法是在我們給某個函數decorator時被調用,所以,需要有一個func的參數,也就是被decorator的函數。
  2. 一個是__call__(),這個方法是在我們調用被decorator函數時被調用的

**如果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 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 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

【更多debug工具 示例】

【flask route】

PythonDecoratorLibrary

關于Python Decroator的各種提案

Python本身提供了一些裝飾器:property,staticmethod

參考鏈接

  1. How can I make a chain of function decorators in Python?
  2. 理解PYTHON中的裝飾器
  3. Python修飾器的函數式編程
  4. Understanding Python Decorators in 12 Easy Steps!
  5. PEP 0318 -- Decorators for Functions and Methods
  6. PEP 3129 -- Class Decorators

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 南平市| 揭东县| 门头沟区| 富锦市| 石林| 上蔡县| 墨竹工卡县| 贡山| 麻栗坡县| 黔西县| 大田县| 绥棱县| 贵德县| 高密市| 鄂托克旗| 广东省| 浙江省| 清河县| 抚远县| 沈丘县| 永州市| 千阳县| 八宿县| 施甸县| 拉萨市| 丰顺县| 理塘县| 罗江县| 苍溪县| 广水市| 玉门市| 和田市| 汕头市| 绥化市| 黄平县| 青海省| 壤塘县| 甘泉县| 孝感市| 镇赉县| 镇赉县|