【问题标题】:capture change of global variable value in python在python中捕获全局变量值的变化
【发布时间】:2020-04-27 17:23:03
【问题描述】:

如何在 python 中检测或捕获全局变量的值变化

variable = 10
print(variable)
variable = 20 
# Detect changes to the value using a signal to trigger a function

更新 AST 文档 - 很好的介绍 https://greentreesnakes.readthedocs.io/en/latest/

【问题讨论】:

  • 我不知道python是否可以做到这一点,但tkinter为此使用类-即。 IntVar() 使用 get()/set() 处理数据,但它也有 tracer(callback) 分配函数,这些函数将在值更改时执行。类似的类 - Properties - 使用 Kivy。所以你可以创建自己的具有类似功能的类。
  • 这是在独立脚本中,还是在更大的应用程序中?因为您可以在循环中使用异步进程来发送信号/标志以在下一个循环中捕获
  • 独立脚本,我希望仅捕获变量值更改@Sparrow1029
  • 如果你将它全部包装在一个while循环中并在每个循环的顶部检测是否有任何变化?抱歉,我对您尝试编写的脚本不了解更多,但通常您需要有一个单独的某种观察者/侦听器进程来检测变量的变化,这通常比单个脚本更复杂...
  • 如果您只能捕获从其他模块应用的更改,是否可以接受?例如在模块a 中有一个全局variable,然后在模块bimport a; a.variable = 123 中。这种特定情况更可行,因为您可以覆盖 import a 产生的模块对象,然后覆盖该对象的 __setitem__。在那一点上,尽管您真的在竭尽全力做一些可能不应该做的事情

标签: python python-3.x variables global-variables globals


【解决方案1】:

如何检测字节码以在存储到全局变量的每个语句之前添加一个打印语句。这是一个例子:

from bytecode import *

def instr_monitor_var(func, varname):
    print_bc = [Instr('LOAD_GLOBAL', 'print'), Instr('LOAD_GLOBAL', varname),
                Instr('CALL_FUNCTION', 1), Instr('POP_TOP')]

    bytecodes = Bytecode.from_code(func.__code__)
    for i in reversed(range(len(bytecodes))):
        if bytecodes[i].name=='STORE_GLOBAL' and bytecodes[i].arg==varname:
            bytecodes[i:i]=print_bc

    func.__code__=bytecodes.to_code()

def test():
    global a
    a = 1
instr_monitor_var(test, 'a')
test()

instr_monitor_var 可以检测函数test,因此全局变量a 将在其值更改时打印出来。让我知道这个是否奏效。谢谢!

【讨论】:

    【解决方案2】:

    据我所知,在 Python 中一般无法捕获全局符号的分配(至少在 CPython 中,全局变量存储在 module 对象中的 dict 中,两者都是 C 类型,不能monkey patched)。

    这是一个简单的解决方法,它有点妥协。使用包装器对象来存储您监控的变量,并定义 __setattr__ 在设置属性之前(或之后)执行您想做的任何事情。

    class CaptureOnSetAttribute:
        def __setattr__(self, attr, value):
            # our hook to do something
            print(f'set value of {attr} to {value}')
            # actually set the attribute the normal way after
            super().__setattr__(attr, value)
    
    
    wrapper_object = CaptureOnSetAttribute()
    

    当然,折衷方案是现在不要写这样的东西:

    monitored_global = value
    

    你现在必须写:

    wrapper_object.monitored_attribute = value
    

    【讨论】:

    • 好的。关于如何修改 ast 和 object 类型类 def 的任何提示?其次,我正在努力寻找 str 的类实现。它是否记录在某处?我看不到对象函数的定义。
    • @Gary 你所说的“ast”和修改它是什么意思?如果你使用的是CPython,那么objecttypestr都是用C实现的,我想大部分相关代码都在这里github.com/python/cpython/tree/master/Objects。如果您正在谈论尝试修改 Python 解释器以满足您的需求,那么我在这里可能超出了我的深度。它也可能超出了此问题的范围,因此您可能需要打开一个新问题以进一步探索
    • 好的,知道了。它是基于 c 的 cpython 实现。我在哪里可以找到使用 ast.Str 类的内容?任何干净的工作示例? '进口 ast' ; 'ast.Str()'
    • @Gary 我个人没有使用过 python 的 ast 库,通过搜索它确实看起来很模糊,但是我能够找到一个“丢失的 Python AST 文档”的站点, greentreesnakes.readthedocs.io/en/latest。 “示例”页面可能对您有所帮助。作为旁注,根据official docs,从 Python 3.8 开始,ast.Str 和其他现在已弃用,由ast.Constant 取代。希望对你有所帮助
    猜你喜欢
    • 2016-06-18
    • 1970-01-01
    • 1970-01-01
    • 2019-07-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-14
    相关资源
    最近更新 更多