python decorators

python decorators

裝飾器基礎

Decorator 本質

@ 本質是語法糖- Syntactic Sugar
使用@decorator 來修飾某個函數 func 時:python

@decorator
def func():
    pass

其解釋器會解釋成:數組

func = decorator(func)

注意這條語句會被執行app

多重裝飾器ide

@decorator_one
@decorator_two
def func():
    pass

至關於:函數

func = decorator_one(decorator_two(func))

帶參數裝飾器url

@decorator(arg1, arg2)
def func():
    pass

至關於:code

func = decorator(arg1,arg2)(func)

使用 *args、**kwargs 給被裝飾函數傳遞參數

def wrapper(func):
    def wrapper_in(*args, **kwargs):
        # args是一個數組,kwargs一個字典
        print("%s is running" % func.__name__)
        return func(*args, **kwargs)
    return wrapper_in

@wrapper
def func(parameter1, parameter2, key1=1):
    print("call func with {} {} {}".format(parameter1, parameter2, key1))


func("haha", None, key1=2)

# func is running
# call func with haha None 2

帶參數的裝飾器

def log(level):
    def decorator(func):
        def wrapper(*args, **kwargs):
            if level == "warn":
                print("%s with warn is running" % func.__name__)
            elif level == "info":
                print("%s with info is running" % func.__name__)
            return func(*args, **kwargs)
        return wrapper

    return decorator


@log("warn")
def foo(*args, **kwargs):
    print("args {}, kwargs{}".format(args, kwargs))

foo(1, 2, a = 3)

# foo with warn is running
# args (1, 2), kwargs{'a': 3}

等同於orm

def foo(name='foo'):
    print("args {}, kwargs{}".format(args, kwargs))

foo = log("warn")(foo)

方法裝飾器

類方法是一個特殊的函數,它的第一個參數 self 指向類實例
因此咱們一樣能夠裝飾類方法對象

def decorate(func):
   def wrapper(self):
       return "<p>{0}</p>".format(func(self))
   return wrapper

class Person(object):
    def __init__(self):
        self.name = "John"
        self.family = "Doe"

    @decorate
    def get_fullname(self):
        return self.name+" "+self.family

my_person = Person()
print my_person.get_fullname()

# <p>John Doe</p>

上例至關於固定了 self 參數,不太靈活
使用 *args, **kwargs傳遞給 wrapper 更加通用:路由

def pecorate(func):
   def wrapper(*args, **kwargs):
       return "<p>{0}</p>".format(func(*args, **kwargs))
   return wrapper

class Person(object):
    def __init__(self):
        self.name = "John"
        self.family = "Doe"

    @pecorate
    def get_fullname(self):
        return self.name+" "+self.family

my_person = Person()

print my_person.get_fullname()

類裝飾器

類實現 __call__ 方法後變成可調用對象,故能夠用類作裝飾器

class EntryExit(object):

    def __init__(self, f):
        self.f = f

    def __call__(self):
        print "Entering", self.f.__name__
        self.f()
        print "Exited", self.f.__name__

@EntryExit
def func1():
    print "inside func1()"

@EntryExit
def func2():
    print "inside func2()"

def func3():
    pass

print type(EntryExit(None))
# func1 變爲類實例
print type(func1)
print type(EntryExit)
# func3 是普通函數
print type(func3)
func1()
func2()

# <class '__main__.EntryExit'>
# <class '__main__.EntryExit'>
# <type 'type'>
# <type 'function'>
# Entering func1
# inside func1()
# Exited func1
# Entering func2
# inside func2()
# Exited func2

類裝飾器

@EntryExit
def func1():
    print "inside func1()"

等同於

def func1():
    print "inside func1()"
# 此處能夠看出 func1 是類EntryExit的一個實例
func1 = EntryExit(myfunc1)

裝飾器裝飾類

register_handles = []


def route(url):
    global register_handles

    def register(handler):
        register_handles.append((".*$", [(url, handler)]))
        return handler

    return register

@route("/index")
class Index():
    def get(self, *args, **kwargs):
        print("hi")

# Index 仍然爲原來定義的類實例
# 至關於在定義類的同時調用裝飾器函數 route, 將該類註冊到全局路由 register_handles
@route("/main")
class Main():
    def get(self, *args, **kwargs):
        print("hi")

print (register_handles)

print(type(Index))

# [('.*$', [('/index', <class __main__.Index at 0x0000000002A49828>)]), ('.*$', [('/main', <class __main__.Main at 0x0000000002FBABE8>)])]
# <type 'classobj'>
@route("/index")
class Index():
    def get(self, *args, **kwargs):
        print("hi")
Index = route("/index")(Index)
# register 返回傳入的 handler,故 Index 仍然爲類對象

functools

上述裝飾器實現有個問題,就是被裝飾函數的屬性被改變

相關文章
相關標籤/搜索