如何在Python中从类对象创建新实例


76

我需要在Python中动态创建类的实例。基本上,我使用load_module和inspect模块将类导入并将其加载到类对象中,但是我不知道如何创建该类对象的实例。

请帮忙!


8
什么?instance = Class()...
Jochen Ritzel 2011年

1
我想您想动态创建一个新类。不是给定类的对象。
jsbueno 2011年

新实例表示在内存中具有自己空间的新对象。大多数语言都使用'new'关键字,因此很明显该对象是新对象,并且新实例(对象)的属性未与其他实例引用/共享。
比尔·罗斯莫斯

由于Python不使用“ new”关键字,因此我在下面用类实例化机制的完整说明更新了答案。
jsbueno

Answers:


124

我想出了我要带到此页面的问题的答案。由于实际上没有人提出我的问题的答案,因此我认为应该发表它。

class k:
  pass

a = k()
k2 = a.__class__
a2 = k2()

此时,a和a2都是同一类(k类)的实例。


2
这似乎是正确的答案。可行,而且很简单。
Miguel Vazq'3

1
请注意,如果init接受 参数,也可以将其传递给构造函数a3 = k2(7)
gerardw

k2 = a.__class__和之间有什么区别k2 = k
Joshua Coady

1
k2是对象类型,在这种情况下为aa.__class)的类型,k2()创建一个独立于的类型的对象的新实例ak2 = k只会创建对同一实例的新引用。
pixelou

2
您还可以使用获取class对象,k2 = type(a)然后调用类对象a2 = k2()。从根本上说是一样的,但是您不必用那些难看的双下划线把代码乱七八糟……也可能更具可移植性
罗伯特·

19

只需使用以下三个参数调用内置的“类型”即可:

ClassName = type("ClassName", (Base1, Base2,...), classdictionary)

如下面的评论中所述更新,这根本不是这个问题的答案。我将不删除它,因为有一些人来到这里尝试动态创建类的提示-这就是上面的代码所做的。

要创建一个类的对象,也要有一个引用,就像接受的答案中所提到的,只需调用该类即可:

instance = ClassObject()

因此,实例化的机制是:

Python不使用new某些语言使用的关键字-相反,它的数据模型解释了使用与任何其他可调用对象相同的语法调用类时用于创建类实例的机制:

__call__调用其类的方法(在类的情况下,其类为“元类”-通常是内置的type)。此调用的正常行为是__new__在要实例化的类上调用(伪)静态方法,然后调用__init__。该__new__方法是负责分配存储器和例如,通常是由完成__new__object,其是类层次的根。

因此调用ClassObject()所调用ClassObject.__class__.call()(通常会type.__call__)这个__call__方法会收到ClassObject本身作为第一个参数-一个纯Python实现是这样的:(CPython的版本是当然的,在C做的,有很多的额外代码cornercases和优化)

class type:
    ...
    def __call__(cls, *args, **kw):
          constructor = getattr(cls, "__new__")
          instance = constructor(cls) if constructor is object.__new__ else constructor(cls, *args, **kw)
          instance.__init__(cls, *args, **kw)
          return instance

(我不记得在文档上看到了将多余参数压制到根__new__并将其传递给其他类的确切理由(或机制)-但这是“在现实生活中”发生的情况-如果object.__new__使用任何额外参数调用它引发类型错误-但是,任何自定义实现__new__都会正常获得额外的参数)


8
OP不想创建实例而不是类吗?
基思

3

Child假设Parent已经存在,这就是您可以动态创建代码中命名的类的方法,即使您没有显式Parent类,也可以使用object...

下面的代码定义__init__()然后将其与该类相关联。

>>> child_name = "Child"
>>> child_parents = (Parent,)
>>> child body = """
def __init__(self, arg1):
    # Initialization for the Child class
    self.foo = do_something(arg1)
"""
>>> child_dict = {}
>>> exec(child_body, globals(), child_dict)
>>> childobj = type(child_name, child_parents, child_dict)
>>> childobj.__name__
'Child'
>>> childobj.__bases__
(<type 'object'>,)
>>> # Instantiating the new Child object...
>>> childinst = childobj()
>>> childinst
<__main__.Child object at 0x1c91710>
>>>

2

如果您的模块带有要导入的类,则可以这样进行。

module = __import__(filename)
instance = module.MyClass()

如果您不知道该类的名称,则可以遍历模块中可用的类。

import inspect
module = __import__(filename)
for c in module.__dict__.values():
    if inspect.isclass(c):
        # You may need do some additional checking to ensure 
        # it's the class you want
        instance = c()
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.