返回顶部
首页 > 资讯 > 后端开发 > Python >带参数的全类型 Python 装饰器
  • 605
分享到

带参数的全类型 Python 装饰器

Python装饰器 2023-05-14 21:05:08 605人浏览 八月长安

Python 官方文档:入门教程 => 点击学习

摘要

这篇短文中显示的代码取自我的小型开源项目按合同设计,它提供了一个类型化的装饰器。装饰器是一个非常有用的概念,你肯定会在网上找到很多关于它们的介绍。简单说,它们允许在每次调用装饰函数时(之前和之后)执行代码。通过这种方式,你可以修改函数参数或

带参数的全类型 Python 装饰器

这篇短文中显示的代码取自我的小型开源项目按合同设计,它提供了一个类型化的装饰器。装饰器是一个非常有用的概念,你肯定会在网上找到很多关于它们的介绍。简单说,它们允许在每次调用装饰函数时(之前和之后)执行代码。通过这种方式,你可以修改函数参数或返回值、测量执行时间、添加日志记录、执行执行时类型检查等等。请注意,装饰器也可以为类编写,提供另一种元编程方法(例如在 attrs 包中完成)

在最简单的形式中,装饰器的定义类似于以下代码:

def my_first_decorator(func):
 def wrapped(*args, **kwargs):
 # do something before
 result = func(*args, **kwargs)
 # do something after
 return result
 return wrapped
@my_first_decorator
def func(a):
 return a

如上代码,因为当定义了被包装的嵌套函数时,它的周围变量可以在函数内访问并保存在内存中,只要该函数在某处使用(这在函数式编程语言中称为闭包)。

很简单, 但是这有一些缺点。最大的问题是修饰函数会丢失它的之前的函数名字(你可以用inspect.signature看到这个),它的文档字符串,甚至它的名字, 这些是源代码文档工具(例如 sphinx)的问题,但可以使用标准库中的 functools.wraps 装饰器轻松解决:

from functools import wraps
from typing import Any, Callable, TypeVar, ParamSpec
P = ParamSpec("P") # 需要python >= 3.10
R = TypeVar("R")
def my_second_decorator(func: Callable[P, R]) -> Callable[P, R]:
 @wraps(func)
 def wrapped(*args: Any, **kwargs: Any) -> R:
 # do something before
 result = func(*args, **kwargs)
 # do something after
 return result
 return wrapped
@my_second_decorator
def func2(a: int) -> int:
 """Does nothing"""
 return a
print(func2.__name__)
# 'func2'
print(func2.__doc__)
# 'Does nothing'

在这个例子中,我已经添加了类型注释,注释和类型提示是对 python 所做的最重要的补充。更好的可读性、IDE 中的代码完成以及更大代码库的可维护性只是其中的几个例子。上面的代码应该已经涵盖了大多数用例,但无法参数化装饰器。考虑编写一个装饰器来记录函数的执行时间,但前提是它超过了一定的秒数。这个数量应该可以为每个装饰函数单独配置。如果没有指定,则应使用默认值,并且应使用不带括号的装饰器,以便更易于使用:

@time(threshold=2)
def func1(a):
...
# No paranthesis when using default threshold
@time
def func2(b):
...

如果你可以在第二种情况下使用括号,或者根本不提供参数的默认值,那么这个秘诀就足够了:

from functools import wraps
from typing import Any, Callable, TypeVar, ParamSpec
P = ParamSpec("P") # 需要python >= 3.10
R = TypeVar("R")
def my_third_decorator(threshold: int = 1) -> Callable[[Callable[P, R]], Callable[P, R]]:
 def decorator(func: Callable[P, R]) -> Callable[P, R]:
 @wraps(func)
 def wrapper(*args: Any, **kwargs: Any) -> R:
 # do something before you can use `threshold`
 result = func(*args, **kwargs)
 # do something after
 return result
 return wrapper
 return decorator
@my_third_decorator(threshold=2)
def func3a(a: int) -> None:
...
# works
@my_third_decorator()
def func3b(a: int) -> None:
...
# Does not work!
@my_third_decorator
def func3c(a: int) -> None:
...

为了涵盖第三种情况,有一些包,即 wraps 和 decorator,它们实际上可以做的不仅仅是添加可选参数。虽然质量非常高,但它们引入了相当多的额外复杂性。使用 wrapt-decorated 函数,在远程集群上运行函数时,我进一步遇到了序列化问题。据我所知,两者都没有完全键入,因此静态类型检查器/ linter(例如 mypy)在严格模式下失败。

当我在自己的包上工作并决定编写自己的解决方案时,必须解决这些问题。它变成了一种可以轻松重用但很难转换为库的模式。

它使用标准库的重载装饰器。这样,可以指定相同的装饰器与我们的无参数一起使用。除此之外,它是上面两个片段的组合。这种方法的一个缺点是所有参数都需要作为关键字参数给出(这毕竟增加了可读性)

from typing import Callable, TypeVar, ParamSpec
from functools import partial, wraps
P = ParamSpec("P") # requires python >= 3.10
R = TypeVar("R
@overload
def typed_decorator(func: Callable[P, R]) -> Callable[P, R]:
...
@overload
def typed_decorator(*, first: str = "x", second: bool = True) -> Callable[[Callable[P, R]], Callable[P, R]]:
...
def typed_decorator(
 func: Optional[Callable[P, R]] = None, *, first: str = "x", second: bool = True
) -> Union[Callable[[Callable[P, R]], Callable[P, R]], Callable[P, R]]:
 """
Describe what the decorator is supposed to do!
Parameters
----------
first : str, optional
First argument, by default "x".
This is a keyword-only argument!
second : bool, optional
Second argument, by default True.
This is a keyword-only argument!
"""
 def wrapper(func: Callable[P, R], *args: Any, **kw: Any) -> R:
 """The actual logic"""
 # Do something with first and second and produce a `result` of type `R`
 return result
 # Without arguments `func` is passed directly to the decorator
 if func is not None:
 if not callable(func):
 raise TypeError("Not a callable. Did you use a non-keyword argument?")
 return wraps(func)(partial(wrapper, func))
 # With arguments, we need to return a function that accepts the function
 def decorator(func: Callable[P, R]) -> Callable[P, R]:
 return wraps(func)(partial(wrapper, func))
 return decorator

稍后,我们可以分别使用我们的不带参数的装饰器

@typed_decorator
def spam(a: int) -> int:
 return a
@typed_decorator(first = "y
def eggs(a: int) -> int:
 return a

这种模式肯定有一些开销,但收益大于成本。

原文:​​https://www.PHP.cn/link/d0f82e1046ccbd597c7f2a7bfba9e7dd​​

以上就是带参数的全类型 Python 装饰器的详细内容,更多请关注编程网其它相关文章!

--结束END--

本文标题: 带参数的全类型 Python 装饰器

本文链接: https://lsjlt.com/news/205691.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 带参数的全类型 Python 装饰器
    这篇短文中显示的代码取自我的小型开源项目按合同设计,它提供了一个类型化的装饰器。装饰器是一个非常有用的概念,你肯定会在网上找到很多关于它们的介绍。简单说,它们允许在每次调用装饰函数时(之前和之后)执行代码。通过这种方式,你可以修改函数参数或...
    99+
    2023-05-14
    Python 装饰器
  • Python带参装饰器
    装饰器(无参)  它是一个函数;  函数作为它的形参;  返回值也是一个函数;  可以使用@functionname方式,简化调用;装饰器和高阶函数  装饰器是高阶函数,但装饰器是对传入函数的功能的装饰(功能增强)import dateti...
    99+
    2023-01-31
    Python
  • 怎么在python中修饰带参数的装饰器
    本篇文章给大家分享的是有关怎么在python中修饰带参数的装饰器,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。python的五大特点是什么python的五大特点:1.简单易学,...
    99+
    2023-06-14
  • python怎么操作带参的装饰器
    这篇文章主要介绍了python怎么操作带参的装饰器的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇python怎么操作带参的装饰器文章都会有所收获,下面我们一起来看看吧。说明装饰函数的第一个参数是装饰func,和...
    99+
    2023-06-30
  • python 装饰器(二): 加参数
    接上篇python 闭包&装饰器(一) 一、功能函数加参数:实现一个可以接收任意数据的加法器 源代码如下: def show_time(f): def inner(*x, **y): # 形参 ...
    99+
    2023-01-30
    参数 python
  • python3--函数的有用信息,带参数的装饰器,多个装饰器装饰同一个函数
    开放封闭原则1 对扩展是开放的    为什么要对扩展开放呢?    我们说,任何一个程序,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改,所以我们必须允许代码扩展,添加新功能2 对修...
    99+
    2023-01-30
    函数 多个 有用
  • 怎么在python中操作带参的装饰器
    本篇文章给大家分享的是有关怎么在python中操作带参的装饰器,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。python可以做什么Python是一种编程语言,内置了许多有效的工...
    99+
    2023-06-14
  • 使用python怎么实现一个带参数的装饰器
    使用python怎么实现一个带参数的装饰器?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。python主要应用领域有哪些1、云计算,典型应用OpenStack。2...
    99+
    2023-06-14
  • python装饰器2:类装饰器
    装饰器1:函数装饰器 装饰器2:类装饰器 装饰器3:进阶 本文是装饰器相关内容的第二篇,关于类装饰器。 "类装饰器"有两种解读方式:用来装饰类的装饰器;类作为装饰器装饰其它东西。你如何认为取决于你,两种说法都有出现在其它的文章中。我的...
    99+
    2023-01-30
    python
  • Python——装饰器(无参)
    装饰器装饰器可以叠加使用,执行是从下到上执行的无参装饰器 @logger1.它是一个语法糖2.函数作为它 的形参3.返回值也是一个函数4.可以使用 @function 方式,简化调用注意: 此处的装饰器的定义并不准确,只是方便理解装饰器和高...
    99+
    2023-01-31
    Python
  • Python装饰器与类的装饰器怎么实现
    这篇“Python装饰器与类的装饰器怎么实现”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Python装饰器与类的装饰器怎么...
    99+
    2023-06-29
  • Python各种类型装饰器详细介绍
    目录装饰器说明装饰器分类最简单的装饰器用于修改对象的装饰器用于模拟对象的装饰器--函数装饰器用于模拟对象的装饰器--类方法装饰器用于模拟对象的装饰器--类装饰器特殊应用的装饰器类实现...
    99+
    2024-04-02
  • Python学习之装饰器与类的装饰器详解
    目录装饰器装饰器的定义装饰器的用法类中的装饰器类的装饰器 - classmethod类的装饰器 - staticmethod类的装饰器 - property通过学习装饰器可以让我们更...
    99+
    2024-04-02
  • Python——编写类装饰器
    编写类装饰器类装饰器类似于函数装饰器的概念,但它应用于类,它们可以用于管理类自身,或者用来拦截实例创建调用以管理实例。 -----------------------------------------------------------...
    99+
    2023-01-31
    Python
  • 周末学习笔记——day02(带参装饰器,
    一,复习 ''' 1.函数的参数:实参与形参 形参:定义函数()中出现的参数 实参:调用函数()中出现的参数 形参拿到实参的值,如果整体赋值(自己改变存放值的地址),实参不会改变,(可变类型)如果修改内部内容,实...
    99+
    2023-01-31
    学习笔记 周末
  • python函数装饰器构造和参数传递
    目录一.闭包函数二.python装饰器构造三.python装饰器叠加四.python装饰器传参1.装饰器单个参数传递2.装饰器多个参数传递3.装饰器的不定长参数五、带返回值的装饰器前...
    99+
    2024-04-02
  • 获取不带类型参数的泛型结构的类型名称
    php小编草莓在这篇文章中将向大家介绍如何获取不带类型参数的泛型结构的类型名称。泛型是一种强大的编程技术,可以在不指定具体类型的情况下编写通用的代码。然而,有时我们可能需要获取泛型结构...
    99+
    2024-02-13
    typedef overflow
  • Golang 装饰器函数的哪些参数
    php小编百草为大家介绍一下Golang装饰器函数的参数。在Golang中,装饰器函数是一种特殊的函数,可以用来包装其他函数,为其添加额外的功能。装饰器函数通常有三个参数:原始函数、装...
    99+
    2024-02-09
  • 浅谈python装饰器探究与参数的领取
    首先上原文: 现在,假设我们要增强now()函数的功能,比如,在函数调用前后自动打印日志,但又不希望修改now()函数的定义,这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)。 ...
    99+
    2022-06-04
    浅谈 参数 python
  • 如何进行Python各种类型装饰器的分析
    这篇文章将为大家详细讲解有关如何进行Python各种类型装饰器的分析,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。装饰器说明Python中的装饰器是一种可以装饰其它对象的工具。该工具本质上是...
    99+
    2023-06-22
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作