覆盖从另一个模块导入的函数中的全局变量 [英] Override globals in function imported from another module

查看:137
本文介绍了覆盖从另一个模块导入的函数中的全局变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有两个模块:

a.py

 value = 3 
def x()
返回值

b.py

 来自导入x 
值= 4

我的目标是使用 ax b 中,但改变函数返回的值。具体而言,即使在运行时, value 也会被查找为 a 作为全局名称的来源> BX()。我基本上试图在 bx 中创建一个与 ax 相同但使用<$ c的函数对象的副本$ c> b 来获取它的全局变量。有没有相当直接的方法来做到这一点?



以下是一个例子:

  import a,b 

print(ax(),bx())

结果目前是 3 3 ,但我希望它是 3 4



我已经提出了两种复杂的方法,但我对任何一种方法都不满意:


  1. 使用复制和粘贴在模块 b 中重新定义 x 。真正的函数比所示的复杂得多,所以这并不适合我。
  2. 定义一个可以传入x的参数,并使用模块的值:

      def x(价值):
    返回值

    这增加了我想避免的用户负担,并且不能真正解决问题。


有没有办法修改函数以何种方式获取其全局变量?

解决方案

我已经通过猜测与检查和研究的混合来提出解决方案。您可以完全按照我在问题中提出的建议:复制函数对象并替换它的 __globals __ 属性。



我使用Python 3,所以这里是 answer 回答上面提到的问题,并添加一个选项来覆盖全局变量:

  import copy 
导入类型
导入functools
$ b def copy_func(f,全局变量=无,模块=无):
基于https:如果globals是None:
globals = f .__ globals__
g = types.FunctionType(f .__ code__,globals) ,name = f .__ name__,
argdefs = f .__ defaults__,closure = f .__ closure__)
g = functools.update_wrapper(g,f)
如果模块不是无:
g .__ module__ = module
g .__ kwdefaults__ = copy.copy(f .__ kw defaults__)
return g

b.py

  from a import x 
value = 4
x = copy_func(x,globals(),__name__)

__ globals __ 属性是只读的,这就是为什么它必须传递给 FunctionType 的构造函数。现有函数对象的 __ globals __ 引用无法更改:为什么是func。 __globals__记录为只读?


Let's say I have two modules:

a.py

value = 3
def x()
    return value

b.py

from a import x
value = 4

My goal is to use the functionality of a.x in b, but change the value returned by the function. Specifically, value will be looked up with a as the source of global names even when I run b.x(). I am basically trying to create a copy of the function object in b.x that is identical to a.x but uses b to get its globals. Is there a reasonably straightforward way to do that?

Here is an example:

import a, b

print(a.x(), b.x())

The result is currently 3 3, but I want it to be 3 4.

I have come up with two convoluted methods that work, but I am not happy with either one:

  1. Re-define x in module b using copy-and paste. The real function is much more complex than shown, so this doesn't sit right with me.
  2. Define a parameter that can be passed in to x and just use the module's value:

    def x(value):
        return value
    

    This adds a burden on the user that I want to avoid, and does not really solve the problem.

Is there a way to modify where the function gets its globals somehow?

解决方案

I've come up with a solution through a mixture of guess-and-check and research. You can do pretty much exactly what I proposed in the question: copy a function object and replace its __globals__ attribute.

I am using Python 3, so here is a modified version of the answer to the question linked above, with an added option to override the globals:

import copy
import types
import functools

def copy_func(f, globals=None, module=None):
    """Based on https://stackoverflow.com/a/13503277/2988730 (@unutbu)"""
    if globals is None:
        globals = f.__globals__
    g = types.FunctionType(f.__code__, globals, name=f.__name__,
                           argdefs=f.__defaults__, closure=f.__closure__)
    g = functools.update_wrapper(g, f)
    if module is not None:
        g.__module__ = module
    g.__kwdefaults__ = copy.copy(f.__kwdefaults__)
    return g

b.py

from a import x
value = 4
x = copy_func(x, globals(), __name__)

The __globals__ attribute is read-only, which is why it must be passed to the constructor of FunctionType. The __globals__ reference of an existing function object can not be changed: Why is func.__globals__ documented as read-only?.

这篇关于覆盖从另一个模块导入的函数中的全局变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆