#python #oop
#python #ооп
Вопрос:
Мне нужно динамически создать экземпляр класса в Python. По сути, я использую модуль load_module и inspect для импорта и загрузки класса в объект класса, но я не могу понять, как создать экземпляр этого объекта класса.
Комментарии:
1. Что?
instance = Class()
…2. Я предполагаю, что вы хотите динамически создавать новый класс. Не является объектом данного класса.
3. новый экземпляр означает новый объект со своим собственным пространством в памяти. большинство языков используют ключевое слово ‘new’, чтобы явно указать, что объект является новым и что на свойства нового экземпляра (object’s) нет ссылок / общего доступа к другому экземпляру.
4. Поскольку Python не использует ключевое слово «new», я обновил свой ответ ниже полным объяснением механизма создания класса.
Ответ №1:
Я выяснил ответ на возникший у меня вопрос, который привел меня на эту страницу. Поскольку никто на самом деле не предложил ответ на мой вопрос, я решил опубликовать его.
class k:
pass
a = k()
k2 = a.__class__
a2 = k2()
На данный момент a и a2 являются экземплярами одного и того же класса (class k).
Комментарии:
1. Кажется, это правильный ответ. Работает, и это просто.
2. Обратите внимание, что вы также можете передать параметры конструктору, если init их принимает
a3 = k2(7)
3. В чем разница между
k2 = a.__class__
иk2 = k
?4.
k2
является ли тип объекта, в данном случае тип dea
(a.__class
),k2()
создающим новый экземпляр объекта этого типа, независимым отa
.k2 = k
просто создал бы новую ссылку на тот же экземпляр.5. вы также можете получить
class
объект с помощьюk2 = type(a)
, а затем вызвать объект классаa2 = k2()
. По сути, это то же самое, но вам не нужно засорять свой код этими уродливыми двойными подчеркиваниями … возможно, это также более переносимо
Ответ №2:
Просто вызовите встроенный «тип», используя три параметра, вот так:
ClassName = type("ClassName", (Base1, Base2,...), classdictionary)
обновить
как указано в комментарии ниже, это вообще не ответ на этот вопрос. Я оставлю это неизмененным, поскольку есть подсказки, которые некоторые люди получают здесь, пытаясь динамически создавать классы — что и делает строка выше.
Для создания объекта класса у каждого тоже есть ссылка, как указано в принятом ответе, нужно просто вызвать класс:
instance = ClassObject()
Механизм создания экземпляра, таким образом:
Python не использует new
ключевое слово, используемое некоторыми языками — вместо этого его модель данных объясняет механизм, используемый для создания мгновенности класса, когда он вызывается с тем же синтаксисом, что и любой другой вызываемый:
Вызывается метод его класса’ __call__
(в случае класса его классом является «метакласс», который обычно является встроенным type
). Нормальным поведением этого вызова является вызов (псевдо) статического __new__
метода для создаваемого экземпляра класса, за которым следует его __init__
. __new__
Метод отвечает за выделение памяти и тому подобное, и обычно выполняется __new__
of object
, который является корнем иерархии классов.
Таким образом, вызов ClassObject()
вызывает ClassObject.__class__.call()
(что обычно и будет type.__call__
) этот __call__
метод получит сам ClassObject в качестве первого параметра — чистая реализация Python была бы такой: (версия CPython, конечно, выполнена на C и с большим количеством дополнительного кода для угловых регистров и оптимизации)
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__
получит дополнительные параметры нормально)
Комментарии:
1. Разве 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>
>>>
Ответ №4:
Если у вас есть модуль с классом, который вы хотите импортировать, вы можете сделать это следующим образом.
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()
Ответ №5:
Если у вас есть какой-либо объект класса, вы можете создать его экземпляр, просто вызвав его (в круглых скобках).
class MyClass: pass
some_class = MyClass
some_instance = some_class() # -> instance of MyClass
Ответ №6:
Я думаю, что аккуратным способом было бы использовать type
. Вот пример:
>>> class Foo:
... def __init__(self, s):
... self.s = s
...
>>> a = Foo("hello")
>>> a.s
'hello'
>>> b = type(a)("world")
>>> b.s
'world'
>>> assert isinstance(a, Foo)
>>> assert isinstance(b, Foo)
b
это экземпляр, который имеет тот же тип, что и a
.