如何使用装饰器将变量注入作用域?

2023-12-08

[免责声明:可能有更多的Python方式来做我想做的事情,但我想知道Python的作用域在这里是如何工作的]

我正在尝试找到一种方法来制作一个装饰器,该装饰器可以执行诸如将名称注入另一个函数的作用域之类的操作(这样该名称就不会泄漏到装饰器的作用域之外)。例如,如果我有一个函数说要打印名为的变量var尚未定义,我想在调用它的装饰器中定义它。这是一个失败的例子:

c = 'Message'

def decorator_factory(value):
    def msg_decorator(f):
        def inner_dec(*args, **kwargs):
            var = value
            res = f(*args, **kwargs)
            return res
        return inner_dec
    return msg_decorator

@decorator_factory(c)
def msg_printer():
    print var

msg_printer()

我想要打印“Message”,但它给出了:

NameError: global name 'var' is not defined

回溯甚至指向哪里var被定义为:

<ipython-input-25-34b84bee70dc> in inner_dec(*args, **kwargs)
      8         def inner_dec(*args, **kwargs):
      9             var = value
---> 10             res = f(*args, **kwargs)
     11             return res
     12         return inner_dec

所以我不明白为什么找不到var.

有什么办法可以做这样的事情吗?


你不能。作用域名称(闭包)是在编译时确定的,您不能在运行时添加更多名称。

您最希望实现的目标就是添加global名称,使用函数的own全局命名空间:

def decorator_factory(value):
    def msg_decorator(f):
        def inner_dec(*args, **kwargs):
            g = f.__globals__  # use f.func_globals for py < 2.6
            sentinel = object()

            oldvalue = g.get('var', sentinel)
            g['var'] = value

            try:
                res = f(*args, **kwargs)
            finally:
                if oldvalue is sentinel:
                    del g['var']
                else:
                    g['var'] = oldvalue

            return res
        return inner_dec
    return msg_decorator

f.__globals__是包装函数的全局命名空间,因此即使装饰器位于不同的模块中,它也能工作。如果var已经定义为全局变量,它被替换为新值,并且在调用该函数后,全局变量被恢复。

这是有效的,因为函数中任何未分配给且未在周围范围中找到的名称都会被标记为全局名称。

Demo:

>>> c = 'Message'
>>> @decorator_factory(c)
... def msg_printer():
...     print var
... 
>>> msg_printer()
Message
>>> 'var' in globals()
False

但除了装饰之外,我还可以定义var在全球范围内directly.

请注意,更改全局变量不是线程安全的,并且对同一模块中其他函数的任何瞬时调用也仍然会看到相同的全局变量。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用装饰器将变量注入作用域? 的相关文章

随机推荐

  • 从下拉菜单中选择并重新加载页面

    我有一个表 它填充来自 MYSQL 数据库的数据并填充来自同一数据库的下拉菜单 我的下拉菜单和表格很好 但我希望能够选择在表格中显示哪些数据
  • JavaScript 无法在 Android Webview 中运行?

    我正在尝试制作一个相对简单的 iOS 应用程序的 Android 版本 该应用程序使用 webview 一些按钮 然后依赖于对 CMS 的 javascript 调用 但我陷入了开发的早期阶段 webview 无法使用 javascript
  • Jupyter 和 PyCharm 中的 Python statsmodels 和简单指数平滑

    我是 python 新手 正在尝试运行thisJupyter 笔记本中的示例 每当我跟着跑 import os import numpy as np import pandas as pd import matplotlib pyplot
  • 存储 Redis 密钥的最佳方式

    我使用 Redis 来存储一些信息并检测这些信息随时间的变化 例如 考虑用户和位置 使用更长或更短的键名有什么价值 使用更长的键更清晰 但是使用更长的键名会带来很大的内存或性能成本吗 以下是示例 SET L 123456
  • 如何为 tomcat-maven-plugin 配置附加上下文路径?

    我使用 Maven 3 0 3 和 Tomcat 插件 我想使用 Maven 和 Tomcat 部署该网站的嵌入式实例 我的问题是如何在嵌入式 Tomcat 服务器中配置附加上下文路径 下面是我的 Tomcat 配置 但是我的
  • python unittest 的 setUp 函数不使用在类上声明的模拟

    所以我正在编写单元测试 但我在设置函数方面遇到了问题 据我所知 它应该在函数之前执行代码 因此我可以将任何重复的内容放在那里 然而 这个函数似乎并没有将我创建的模拟应用为整个类的补丁装饰器 这是我希望它看起来像的一小部分 patch geo
  • Java MySQL的executeUpdate()对于INSERT ON ON DUPLICATE KEY UPDATE返回什么?

    我在网上查了大约3个小时 仍然找不到这个问题的答案 爪哇文档还有这个tutorial says 返回 1 SQL 数据操作语言的行计数 DML 语句或 2 0 表示不返回任何内容的 SQL 语句 那么这意味着 插入 1 行无重复项 gt 1
  • 尽管已安装,但未找到底图数据雇用

    我和这个帖子有同样的问题 使用辅助脚本中的导入来声明 var 可由另一个函数使用 但答案在我这边不起作用 对于上下文 basemap and basemap data hires已安装 但使用时resolution f 它会触发以下错误 O
  • 将 MJPEG 流式传输到文件,但仅保留最后 x 分钟

    我希望在检测到运动时记录 MJPEG 流 但我的运动检测通知比运动发生晚了几秒钟 为了解决这个问题 我想一直录制 但只保留最后 2 分钟的镜头 现在我正在使用 cURL 无限下载 但我一直在思考如何让它将文件的前面正确地修剪为 2 分钟 L
  • 纯CSS棋盘,带有div且没有类或id,可能吗?

    我有以下布局 div div div div div div div div div div div div div div div div div div div div div div div div div div div div d
  • 通知操作图标未显示

    我尝试在 Android 中显示通知 并使用来自这个链接 在一些消息来源中 人们说图标应该是全白色的 而一些消息来源说我应该使用 png代替vector 我尝试了所有这些方法 但没有人帮助我 我尝试这段代码 Notification new
  • 搜索数据库 JavaScript

    我已经消除了所有语法错误 但无法检索任何数据 任何帮助将不胜感激 db 变量存储我正在查找的视频数组 它是一个单独的 js 文件 数据库 var db JavaScript Version History http http wddbs c
  • 有人可以帮我使用 livestream 的 api 发出跨域 xml 请求吗?

    我正在尝试使用 livestream 非常有用的移动 api 位于http www livestream com userguide title Mobile API Requesting a mobile stream发出 xml 请求
  • 如何在 django 中为每个模型关联多种类型的标签

    我对 django 不太陌生 并试图找到最好的方法来做事 而不是自己编写所有内容 我正在开发一个模型 其中需要将多种类型的标签与模型关联 然后我想使用多个过滤条件检索对象 我看到在 django tagging 中 标签是按模型存储的 所以
  • 当两个应用程序都使用嵌入式 activemq 时,如何将 Jms 消息从一个 spring-boot 应用程序发送到另一个应用程序

    我有两个 spring boot 应用程序 在接收器应用程序的 Application java 中我有 Bean public JmsListenerContainerFactory
  • 在 WebAPI 中将 HttpResponseMessage 作为 excel 文件返回的问题

    我创建了 WebAPI 它使用 closexml nuget 返回一个 excel 文件 基本上它改变了我的DataTable脱颖而出 我指的是下面的几个链接 如何在 ASP NET WebAPI 中返回文件 FileContentResu
  • 在 Flutter 中访问 Firebase 存储

    我对 Flutter 相当陌生 以前从未使用过 Firebase 所以如果有明显的解决方案 我深表歉意 我正在开发一个 Flutter 应用程序 其中涉及记录表单提交并将其提交到中央位置 Firebase Storage 似乎很合适 因为据
  • 获取 GeoPandas 中几何图形之间的交集计数

    是否可以使用 GeoPandas 对象获取两个几何图形之间的交集计数 也就是说 我想计算一个 GeoDataFrame 中与另一个 GeoDataFrame 中的每个多边形相交的多边形或线串的数量 在浏览 GeoPandas 文档时 我没有
  • 寻找 C# 注册表类 [已关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 目前不接受答案 寻找包装调用以执行以下操作的 C 类 读取和写入键值 读取和写入密钥条目 枚举键中的条目 这个很重要 例如 需要列出以下位置的所有条目 HKEY L
  • 如何使用装饰器将变量注入作用域?

    免责声明 可能有更多的Python方式来做我想做的事情 但我想知道Python的作用域在这里是如何工作的 我正在尝试找到一种方法来制作一个装饰器 该装饰器可以执行诸如将名称注入另一个函数的作用域之类的操作 这样该名称就不会泄漏到装饰器的作用