繁体   English   中英

重载在Python中使用全局变量的导入函数

[英]Overload imported function that uses globals in Python

有点类似于带有导入的全局变量 -但带有函数。

说我有main_file.py

global main_var1, main_var2

main_var1 = ""
main_var2 = 0

def main():
  for gkey, gval in sorted(globals().items()):
    print("  mf_glb", gkey, "is", type(gval), "and is equal to ", gval)
  for name in dir():
    myvalue = eval(name)
    print("  mf_dir", name, "is", type(myvalue), "and is equal to ", myvalue)

  setup()

  print("main_file says", main_var1, main_var2, "  setup is " + str(eval("setup")))

def setup():
  global main_var1, main_var2
  main_var1 = "Initialized"
  main_var2 = -123  

if __name__ == "__main__":
  main()

如果我直接运行main_file.py ,它将输出(按预期):

...
('main_file says', 'Initialized', -123, '  setup is <function setup at 0xb766d17c>')

现在说,我要使用main_file.py所有其他main_file.py (包括main()函数); 但我想重载setup()以便它设置不同的变量; 所以我尝试作为user_file.py

global main_var1, main_var2

for gkey, gval in sorted(globals().items()):
  print("  uf1_glb", gkey, "is", type(gval), "and is equal to ", gval)
for name in dir():
  myvalue = eval(name)
  print("  uf1_dir", name, "is", type(myvalue), "and is equal to ", myvalue)
print()


from main_file import * 

for gkey, gval in sorted(globals().items()):
  print("  uf2_glb", gkey, "is", type(gval), "and is equal to ", gval)
for name in dir():
  myvalue = eval(name)
  print("  uf2_dir", name, "is", type(myvalue), "and is equal to ", myvalue)
print()

print("A: setup is " + str(eval("setup")))

def setup():
  global main_var1, main_var2
  main_var1 = "Overloaded"
  main_var2 = 42

print("B: setup is " + str(eval("setup")))

main() # since main is not def'd in here (user_file), this will call the one from main_file

如果我使用python user_file.py运行它, python user_file.py得到类似以下内容的信息:

('  uf2_glb', 'setup', 'is', <type 'function'>, 'and is equal to ', <function setup at 0xb7709374>)
('  uf2_dir', 'setup', 'is', <type 'function'>, 'and is equal to ', <function setup at 0xb7709374>)
...
A: setup is <function setup at 0xb7709374>
B: setup is <function setup at 0xb7709a74>
...
('  mf_glb', 'setup', 'is', <type 'function'>, 'and is equal to ', <function setup at 0xb7709374>)
...
('main_file says', 'Initialized', -123, '  setup is <function setup at 0xb7709374>')

因此,基本上,我的重载setup()处于0xb7709a74 ,仅在user_file更改; main_file仍然使用旧setup()0xb7709374 ,所以我的预期变化超载不打印。

从上面链接的问题答案具有从教程,说明一个副本:

实际上,模块中的全局变量仅仅是该模块的属性(即成员实体),类似于类变量在类中的角色。 当模块A导入模块B时,B的名称空间将复制到A的名称空间。 如果模块B具有全局变量X,则模块A将创建该名称的变量,其初始值是模块B在导入时具有该名称的变量的值。 但是其中一个模块对X的更改不会反映在另一个模块中。

因此,有没有办法从user_file重载main_file的功能? 事情可能会变得更加困难,因为setup()实际上使用main_file的全局变量来工作...

确实,似乎有。 首先请注意,您可以使用inspect模块获取Python函数的源代码 然后,原则上,您可以在user_file.py中获得setup()函数的(新)源,并将其“发送”到main_file.py的函数中,在该函数中可以execeval无法接受def ) -但这必须在全局上下文中完成(在main_file.py ),以便在通过exec运行def时替换指向旧函数的全局符号。

或例如-在OP的user_file.py上方,只需将其添加到main之前:

# ...

import inspect
setupsrc = inspect.getsource(setup)
setsetup(setupsrc)

main()

...并添加新的功能, setsetup()main_file.py

def setsetup(instr):
  #global setup # no need, globals() below takes care of it
  cc=compile(instr,'abc','single')
  #print(cc)
  # <code object <module> at 0xb77d1218, file "abc", line 1>
  print("ss1", str(setup))
  exec(cc, globals()) # globals() here does the trick
  print("ss2", str(setup))

然后,当我运行python user_file.py ,我得到:

...
A: setup is <function setup at 0xb774717c>
B: setup is <function setup at 0xb77476f4>
...
('ss1', '<function setup at 0xb774717c>')
('ss2', '<function setup at 0xb775a924>')
...
('  mf_glb', 'setup', 'is', <type 'function'>, 'and is equal to ', <function setup at 0xb775a924>)
...
('main_file says', 'Overloaded', 42, '  setup is <function setup at 0xb775a924>')

...表明函数已按预期重载(即使它不是正在运行的user_file.pysetup()实例-而是带有main_file的源副本)。

PS:请注意,任何def函数都还具有__code__属性,其对象类型与compile()的输出相同(与此相关的是在Python中,我如何获取函数中使用的全局变量? )-但是,我在这里不能真正使用它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM