我有一个定义类和函数的模块:
#barbaz.py
class Bar:
pass
def baz():
return "hello"
在另一个模块中,我有一个带有eval语句的函数:
#foo.py (version 1)
def foo(baz: callable):
bazstr: str = baz.__name__
print(bazstr)
try:
f=eval(f'{bazstr}()')
print(f'result: {f}')
except Exception as e:
print(f"eval error: {e}")
最后,我在另一个模块中进行了测试:
#test.py
from evalf import foo
from barbaz import baz, Bar
#This works...
foo(baz)
#This doesn't
foo(Bar)
baz
有效,但Bar
无效。我得到输出:
baz
result: hello
Bar
eval error: name 'Bar' is not defined
eval
似乎无法使用从模块导入的类,除非它与foo()
函数直接导入到同一模块中。也就是说,这是有效的:
#foo.py (version 2)
from barbaz import Bar
def foo(baz: callable):
bazstr: str = baz.__name__
print(bazstr)
try:
f=eval(f'{bazstr}()')
print(f'result: {f}')
except Exception as e:
print(f"eval error: {e}")
foo(Bar)
为什么foo.py
的版本2可以工作,而版本1抛出了所示的错误?
如何绕过这一点,并在eval语句中使用导入的类,该语句位于它自己的模块中?
foo.py
无法按预期工作,因为它在全局命名空间中没有类或函数(eval
在此处查找本地范围中找不到的名称(。它对函数有效,因为完全巧合的是,外部函数(baz
(和参数名称(baz
(是相同的。它根本没有看到def baz
函数,而是看到了您命名的参数(巧合的是(baz
。
解决方案是只使用您无条件收到的参数的名称;如果必须使用eval
,只需将其中可调用的名称硬编码为baz
,因为它在本地作用域中总是被称为。您可能不应该使用eval
(在您的代码中,f = baz()
可以很好地完成这项工作(,但如果必须使用,那就是解决方案。
问题是foo
函数中有baz
,而没有Bar
。
def foo(baz: callable):
bazstr: str = baz.__name__
print(bazstr)
try:
f = eval(f'{bazstr}()')
print(f'result: {f}')
except Exception as e:
print(f"eval error: {e}")
使用eval
是危险的,您可以简单地在可调用参数旁边添加()
。我把你的三个文件中的代码放在一个文件中,因为单独的文件不会改变它的作用:
class Bar:
pass
def baz():
return "hello"
def foo(baz: callable):
try:
f = baz()
print(f'result: {f}')
except Exception as e:
print("Not callable.")
foo(baz)
foo(Bar)
输出:
result: hello
result: <__main__.Bar object at 0x0000020EA3496E48>