Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

python decorators #7

Open
TheBigFish opened this issue Nov 29, 2018 · 0 comments
Open

python decorators #7

TheBigFish opened this issue Nov 29, 2018 · 0 comments

Comments

@TheBigFish
Copy link
Owner

python decorators

装饰器基础

Decorator 本质

@ 本质是语法糖- Syntactic Sugar
使用@decorator 来修饰某个函数 func 时:

@decorator
def func():
    pass

其解释器会解释成:

func = decorator(func)

注意这条语句会被执行

多重装饰器

@decorator_one
@decorator_two
def func():
    pass

相当于:

func = decorator_one(decorator_two(func))

带参数装饰器

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

相当于:

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}

等同于

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

上述装饰器实现有个问题,就是被装饰函数的属性被改变

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant