Python 装饰器の用法

f众所周知,Python有一个很像Java注解的东西,叫做装饰器

又众所周知,装饰器本质是一个高阶函数, 使用@符号调用装饰器相当于将该函数传入装饰器的参数再赋值给原函数

也就是说这段代码

@decorator
def fun(*args):
    ...

相当于这段代码

def fun(*args):
    ...

fun = decorator(fun)

好,基础的装饰器原理讲完了,接下来我们来尝试一下一些奇怪的装饰器——

带参数的装饰器

我们有时候见过一些带参数的装饰器, 比如像这种 

@App(title="Hello World!")
def MyApp():
    ...

 其实这种“装饰器”就是一个返回装饰器的函数,也就是这段代码中 " App(title="Hello world!") "这个是一个部分,它返回一个装饰器,装饰了MyApp这个函数

这个App函数签名大概就长这样:

def App(*, title: str, ...) -> Callable[[Callable[[...], None]], Callable[[...], None]]

装饰类的装饰器

我们也见过修饰类的装饰器, 比如dataclasses模块中的数据类装饰器@dataclass:

@dataclass
class PointType:
    x: float
    y: float

这种装饰器是如何实现的呢?

其实也是跟普通装饰器差不多,只是将传入装饰器的参数和装饰器的返回值修改为Type类型,就比如这样的装饰器:

def ClassDecorator(clss: Type[object]) -> Type[object]:
    class _inner_class(clss):
        def __init__(self, *args, **kwargs) -> None:
            super().__init__(*args, **kwargs)
            print("Decorated Class.")
    return _inner_class

……然后这样修饰…… 

@ClassDecorator
class MyClass:
    def __init__(self, *args, **kwargs)-> None:
        ...

这样当我们创建MyClass对象, 相当于创建了一个_inner_class类的对象,执行完MyClass的__init__方法的代码后,然后打印"Decorated Class."字符串

其他离谱的装饰器玩法

使用lambda做装饰器

没错, python支持使用lambda表达式做装饰器!

这意味着你的代码甚至可以这样子写……

@(lambda fun: (lambda : fun("Hello world")))
def hello(s: str) -> None:
    print(s)

# 相对之下正经的装饰器写法

def __helloworld_decorator(fun: Callable[[str], None]) -> Callable[[], None]]:
    def __closure_fun() -> None:
        fun("Hello world")
    return __closure_fun

@__helloworld_decorator
def hello(s: str) -> None:
    print(s)

# 相等于

def hello() -> None:
    print("Hello world")

当然, 不建议直接使用lambda作为装饰器,这样做又麻烦又降低可读性。

使用Functor(可调用对象)做装饰器

python也允许使用带__call__方法的类实例对象作为函数的装饰器

比如这样的:

class DecoratorClass:
    def __init__(self):
        ...
    
    def hello(self)-> None:
        print("hello")
    
    def __call__(self, fun) -> fun:
        def hel():
            print("pre decorated")
            fun()
        return hel

#可以这样使用

dec = DecoratorClass()

@dec
def pr() -> None:
    print(dec.hello())
使用装饰器的写法使用某些函数

借助装饰器的性质,我们可以将某些高阶函数当做装饰器来用

比如Pyside6中的信号绑定槽函数我们就可以使用装饰器优雅地来写——

@Btn.clicked.connect
@Slot()
def _() -> None:
    # When the Btn click
    ...

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值