你好开发者,
我正在编写代码,该代码接受用户输入并根据输入初始化类,如下面的示例代码所示:
class X:
def __init__(self):
return
def run(self):
print("i am X")
def func1(cls):
exec("global " + cls.lower())
exec(cls.lower() + " = " + cls + "()")
def func2(mode_to_set):
exec(mode_to_set.lower() + ".run()")
但是当我运行这样的代码时:
func1('X')
func2('X')
我一直收到这个错误:
Traceback (most recent call last):
File "/Users/noahchalifour/Desktop/test.py", line 16, in <module>
func2('X')
File "/Users/noahchalifour/Desktop/test.py", line 13, in func2
exec(mode_to_set.lower() + ".run()")
File "<string>", line 1, in <module>
NameError: name 'x' is not defined
任何人都可以帮助我吗?
答案 0 :(得分:1)
基于用户输入实例化类的更好方法是使用&#34;工厂模式&#34;:
http://python-3-patterns-idioms-test.readthedocs.io/en/latest/Factory.html
基本上,您创建了一个类,其目的是基于值创建其他类。有些人可能会发现过度杀伤,所以你也可以使用一个根据输入创建类的函数。
无论你做什么,现在的方式,使用exec运行原始的用户输入字符串,是个坏主意。最好的情况是,它引入了几乎不可能跟踪的新错误,因为它们实际上并未记录在任何地方。在最糟糕的情况下,用户以某种方式找到了将字符串发送到函数的方法,你几乎已经破坏了你所希望的任何安全性。
基本上&#34; exec&#34;通常应该是最后的手段。通常有更优雅和安全的方法来解决问题。
答案 1 :(得分:0)
似乎你最好让func2
实例化并运行该方法:
def func2(mode_to_set):
globals()[mode_to_set]().run()
通过这种方式,您在全局命名空间中没有一大堆不受欢迎的错误,并且您最终不会执行不受信任的exec
。此外,exec
函数内的global
语句不起作用(如您所见)... exec
是一种执行字符串的方式,就像它是代码一样。 不是将动态创建的语句放入当前函数的方法。
答案 2 :(得分:0)
字典,词典,词典。您的程序应该保持对执行代码的控制,而不是让用户动态构造新代码。
classes = {'X': X}
instances = {}
def func1(cls):
var = cls.lower()
instances[var] = classes[cls]()
def func2(mode_to_set):
instances[mode_to_set.lower()].run()
func1('X')
func2('X')
唯一的区别是你没有名为x
的全局变量;你有一个全球字典,其中包含一个引用你的实例的密钥x
。