Як створити новий екземпляр з об’єкта класу в Python


77

Мені потрібно динамічно створювати екземпляр класу в Python. В основному я використовую модуль load_module та inspect для імпорту та завантаження класу в об'єкт класу, але я не можу зрозуміти, як створити екземпляр цього об'єкта класу.

Будь ласка, допоможіть!


8
Що? instance = Class()...
Йохен Рітцель,

1
Я припускаю, ви хочете динамічно створити новий клас. Не є об’єктом даного класу.
jsbueno

новий екземпляр означає новий об'єкт із власним простором у пам'яті. більшість мов використовують ключове слово 'new', щоб було явно, що об'єкт є новим, і що властивості нового екземпляра (об'єкта) не посилаються / діляться з іншим екземпляром.
Білл Росмус

Оскільки Python не використовує "нове" ключове слово, я оновив свою відповідь нижче з повним поясненням механізму створення класу.
jsbueno

Відповіді:


124

Я з’ясував відповідь на своє запитання, яке привело мене до цієї сторінки. Оскільки насправді ніхто не запропонував відповіді на моє запитання, я подумав, що опублікую.

class k:
  pass

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

На даний момент a і a2 обидва є екземплярами одного класу (клас k).


2
Здається, це правильна відповідь. Працює, і це просто.
Мігель Вазк 03.03.15

1
Зверніть увагу , ви можете також передати параметри конструктору, якщо INIT приймає їх a3 = k2(7)
gerardw

Яка різниця між k2 = a.__class__та k2 = k?
Джошуа Коді

1
k2є типом об'єкта, в даному випадку de type a( a.__class), k2()створити новий екземпляр об'єкта цього типу, незалежний від a. k2 = kпросто створив би нове посилання на той самий екземпляр.
pixelou

2
Ви також можете отримати classоб'єкт, k2 = type(a)а потім викликати об'єкт класу a2 = k2(). Це принципово те ж саме, але вам не потрібно засипати свій код цими потворними подвійними підкресленнями ... може бути і більш портативним
Роберт,

20

Просто зателефонуйте введеному типу, використовуючи три параметри, наприклад:

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 як перший параметр - реалізація Pure 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__воно викликається з будь-якими додатковими параметрами, викликає помилку типу - однак, будь-яка спеціальна реалізація a __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()
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.