【问题标题】:how to dynamically create an instance of a class in python?如何在python中动态创建一个类的实例?
【发布时间】:2010-08-10 17:37:54
【问题描述】:

我有一个类名列表,想动态创建它们的实例。例如:

names=[
'foo.baa.a',
'foo.daa.c',
'foo.AA',
 ....
]

def save(cName, argument):
 aa = create_instance(cName) # how to do it?
 aa.save(argument)

save(random_from(names), arg)

如何在 Python 中动态创建实例?谢谢!

【问题讨论】:

    标签: python


    【解决方案1】:

    假设您已经使用类似的方法导入了相关类

    from [app].models import *
    

    你需要做的就是

    klass = globals()["class_name"]
    instance = klass()
    

    【讨论】:

    • 漂亮的答案。
    • 你为什么把它命名为klass?这个词有什么特殊含义吗?
    • 适用于 django 模型
    • @Nyxynyx 查看“保留字”的编程概念;您通常希望避免在您正在使用的语言和库中用作对象和函数名称的单词
    • 这里倾向于假设......这要求该类已经存在,而我想定义一个具有动态名称的新类
    【解决方案2】:

    这通常称为反思,有时也称为内省。查看一个类似的问题,这些问题可以为您尝试做的事情提供答案:

    Does Python Have An Equivalent to Java Class forname

    Can You Use a String to Instantiate a Class in Python

    【讨论】:

    【解决方案3】:

    这对我有用:

    from importlib import import_module
    
    class_str: str = 'A.B.YourClass'
    try:
        module_path, class_name = class_str.rsplit('.', 1)
        module = import_module(module_path)
        return getattr(module, class_name)
    except (ImportError, AttributeError) as e:
        raise ImportError(class_str)
    

    【讨论】:

    • 非常适合我!谢谢!!
    • 是的,使用 importlib 来解析类比使用星型导入等反模式手动处理要好得多。从 python 3.3 开始,这个答案是最好的解决方案。
    【解决方案4】:

    您通常可以完全避免其中的字符串处理部分。

    import foo.baa 
    import foo.AA
    import foo
    
    classes = [ foo.baa.a, foo.daa.c, foo.AA ]
    
    def save(theClass, argument):
       aa = theClass()
       aa.save(argument)
    
    save(random.choice(classes), arg)
    

    请注意,我们不使用类名的字符串表示。

    在 Python 中,您可以只使用类本身。

    【讨论】:

    • 假设数组来自数据库。所以这个解决方案没有帮助。
    • 好吧,你就这么做type(cName)(**arguments)
    【解决方案5】:

    您可以使用 python 内置的eval() 语句来实例化您的类。 像这样:

    aa = eval(cName)()
    

    注意!

    使用 eval 是危险的,并且是许多基于代码注入的安全风险的关键。

    【讨论】:

    • 不要使用 eval,因为它容易受到安全问题的影响。
    • 它是如何受到影响的?
    • 取决于上下文,如果 cName 来自用户的一些输入,这是很危险的,因为黑客可以在那里注入 Python 代码:这是真的,但很多时候你只需要这个来设置你的应用程序来自仅由开发人员/管理员控制的文本文件或环境变量,在这种情况下足够安全且简单。
    • 即使不使用eval 也存在安全问题,因为攻击者可以实例化任何他想要的类。我的观点是:应进一步分析此实施要求以确保安全。
    【解决方案6】:

    我的问题是我想将参数传递给__init__,并在命令行的字符串中指定参数。例如,相当于

    import a.b.ClassB as ClassB
    instance = ClassB.ClassB('World')
    

    命令行上的字符串是"a.b.ClassB.ClassB('World')"

    在模块 a.b.ClassB 中有以下类

    class ClassB():
    
        def __init__(self, name:str):
            self._name = name
    
        def hello(self):
            print("Hello " + self._name + "!")
    

    我们可以用下面的方法创建这个类

    import importlib
    
    def create_instance(class_str:str):
        """
        Create a class instance from a full path to a class constructor
        :param class_str: module name plus '.' plus class name and optional parens with arguments for the class's
            __init__() method. For example, "a.b.ClassB.ClassB('World')"
        :return: an instance of the class specified.
        """
        try:
            if "(" in class_str:
                full_class_name, args = class_name = class_str.rsplit('(', 1)
                args = '(' + args
            else:
                full_class_name = class_str
                args = ()
            # Get the class object
            module_path, _, class_name = full_class_name.rpartition('.')
            mod = importlib.import_module(module_path)
            klazz = getattr(mod, class_name)
            # Alias the the class so its constructor can be called, see the following link.
            # See https://www.programiz.com/python-programming/methods/built-in/eval
            alias = class_name + "Alias"
            instance = eval(alias + args, { alias: klazz})
            return instance
        except (ImportError, AttributeError) as e:
            raise ImportError(class_str)
    
    if __name__ == "__main__":
        instance = create_instance("a.b.ClassB.ClassB('World')")
        instance.hello()
    

    【讨论】:

      【解决方案7】:

      我找到的最佳答案: 更好的方法是制作字典: 对象 ={} 名称 =[object1,object2,object3]

      对于名称中的 objname: 对象[objname]=类名()

      发现于: https://www.thecodingforums.com/threads/create-object-name-from-string-value.712461/

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多