python decorators_python decorators

戴鸿羲
2023-12-01

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 "

{0}

".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()

#

John Doe

上例相当于固定了 self 参数,不太灵活

使用 *args, **kwargs传递给 wrapper 更加通用:

def pecorate(func):

def wrapper(*args, **kwargs):

return "

{0}

".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()

#

#

#

#

# 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', )]), ('.*$', [('/main', )])]

#

@route("/index")

class Index():

def get(self, *args, **kwargs):

print("hi")

Index = route("/index")(Index)

# register 返回传入的 handler,故 Index 仍然为类对象

functools

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

 类似资料:

相关阅读

相关文章

相关问答