A method in Python that dynamically creates a class instance

  • 2020-05-27 06:14:15
  • OfStack

Introduction to the

In Java we can create class instances based on the class name by reflection, so how do we implement similar functionality in Python?

There is actually an builtin function, import, that you can use to dynamically load modules at runtime. As follows:


def createInstance(module_name, class_name, *args, **kwargs):
  module_meta = __import__(module_name, globals(), locals(), [class_name])
  class_meta = getattr(module_meta, class_name)
  obj = class_meta(*args, **kwargs)
  return obj

example

First we create a directory my_modules, which contains three files

* init.py: module file
* my_module. py: test module
* my_another_module: another module for testing

my_module.py


from my_modules.my_another_module import *
class MyObject(object):
  def test(self):
    print 'MyObject.test'
    MyObject1().test()
    MyObject2().test()
    MyAnotherObject().test()
class MyObject1(object):
  def test(self):
    print 'MyObject1.test'
class MyObject2(object):
  def test(self):
    print 'MyObject2.test'

my_another_module.py


class MyAnotherObject(object):
  def test(self):
    print 'MyAnotherObject.test'

test.py


def createInstance(module_name, class_name, *args, **kwargs):
  module_meta = __import__(module_name, globals(), locals(), [class_name])
  class_meta = getattr(module_meta, class_name)
  obj = class_meta(*args, **kwargs)
  return obj
obj = createInstance("my_modules.my_module", "MyObject")
obj.test()
MyObject.test
MyObject1.test
MyObject2.test
MyAnotherObject.test

pyinstaller integration

For an application packaged with pyinstaller, if you use the above code, running the packaged program will result in the following error


Traceback (most recent call last):
 File "test.py", line 12, in <module>
  obj = createInstance("my_modules.my_module", "MyObject")
 File "test.py", line 7, in createInstance
  module_meta = __import__(module_name, globals(), locals(), [class_name])
ImportError: No module named my_modules.my_module
Failed to execute script test

The reason for the error here is that pyinstaller failed to analyze the module below my_modules when packaging the analysis class, so it ran an error report.

Solution 1:

In test.py, the module under my_modules is manually import, as shown in line 1 below. That's the easiest way to do it, but it's obviously not very good.


import my_modules.my_module
def createInstance(module_name, class_name, *args, **kwargs):
  module_meta = __import__(module_name, globals(), locals(), [class_name])
  class_meta = getattr(module_meta, class_name)
  obj = class_meta(*args, **kwargs)
  return obj
obj = createInstance("my_modules.my_module", "MyObject")
obj.test()

Solution 2:

When using pyinstaller for packaging, specify "wok wok 68en-import", as shown below


pyinstaller -D --hidden-import my_modules.my_module test.py

Solution 3:

Dynamically modify the python runtime path, as shown in the first two lines of the code below, where path can be passed in as an environment variable or parameter. Obviously this method is much more flexible than the first two.


import sys
sys.path.append(...)
def createInstance(module_name, class_name, *args, **kwargs):
  module_meta = __import__(module_name, globals(), locals(), [class_name])
  class_meta = getattr(module_meta, class_name)
  obj = class_meta(*args, **kwargs)
  return obj
obj = createInstance("my_modules.my_module", "MyObject")
obj.test()

Related articles: