75

I have list of class names and want to create their instances dynamically. for example:

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)

How to dynamically create that instances in Python? thanks!

Nyambaa
  • 38,988
  • 9
  • 29
  • 35

7 Answers7

100

Assuming you have already imported the relevant classes using something like

from [app].models import *

all you will need to do is

klass = globals()["class_name"]
instance = klass()
elewinso
  • 2,453
  • 5
  • 22
  • 27
27

This is often referred to as reflection or sometimes introspection. Check out a similar questions that have an answer for what you are trying to do:

Does Python Have An Equivalent to Java Class forname

Can You Use a String to Instantiate a Class in Python

Community
  • 1
  • 1
Scott Lance
  • 2,239
  • 1
  • 18
  • 19
  • 1
    Some of those examples use `__import__`, for newer code you can switch to `importlib` http://docs.python.org/dev/library/importlib.html . (py>=2.7 | >=3.1) – SiggyF Aug 10 '10 at 17:56
  • 15
    Don't use links, please provide a real description. – shadowbq Apr 25 '17 at 12:30
18

This worked for me:

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)
Tobias Ernst
  • 4,214
  • 1
  • 32
  • 30
  • 3
    Works great for me! Thank you!! – Mike Gordo Oct 19 '19 at 17:52
  • 6
    Yeah, using importlib to resolve the class is way better than handling it manually with anti-patterns like star-imports. This answer is, as of python 3.3, the best solution. – Arne Feb 01 '21 at 15:27
10

You can use the python builtin eval() statement to instantiate your classes. Like this:

aa = eval(cName)()

Notice!

using eval is dangerous and is a key for lots of security risks based on code injections.

Community
  • 1
  • 1
hb2pencil
  • 892
  • 1
  • 8
  • 13
  • 7
    Don't use eval as it is susceptible to security issues. – Necrolyte2 Mar 22 '13 at 18:18
  • 2
    and how is it susceptible? – Ujjaval Moradiya Dec 06 '17 at 11:34
  • 2
    Depends of the context, if `cName` comes from some input from a user, it's dangers because a hacker can inject Python code there: it's true, but many times you only need this to setup your application from a text file or an environment variable that is controlled only by developers / admins, in this case is secure enough and simple. – Mariano Ruiz Apr 20 '18 at 14:42
  • 1
    The security issue exist even when not using `eval` as attacker can instanciate any class he wants. My point is: this implementation requirement should be furthered analyzed to be secure. – Tomer W May 20 '21 at 14:00
8

You can often avoid the string processing part of this entirely.

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)

Note that we don't use a string representation of the name of the class.

In Python, you can just use the class itself.

S.Lott
  • 384,516
  • 81
  • 508
  • 779
3

My problem was that I wanted to pass arguments into __init__ with the arguments being specified in a string on the command line. For example, the equivalent of

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

The string on the command line is "a.b.ClassB.ClassB('World')"

With the following class in module a.b.ClassB

class ClassB():

    def __init__(self, name:str):
        self._name = name

    def hello(self):
        print("Hello " + self._name + "!")

we can create this class with the following

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()
David Wood
  • 434
  • 1
  • 5
  • 14
0

Best Answer I found: Better Way is to make a dictionary: objects ={} Names =[object1,object2, object3]

For objname in Names: objects[objname]=classname()

Found in: https://www.thecodingforums.com/threads/create-object-name-from-string-value.712461/

Nic
  • 11