77

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?

7 Answers 7

104

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()
Sign up to request clarification or add additional context in comments.

4 Comments

Why did you name it klass? Does this word have a special meaning?
Works with django models
@Nyxynyx check out the programming concept of a "reserved word;" you typically want to avoid word that are commonly used as object and function names in the language and libraries you are using
to lean into the assumption here... this requires that the class already exist, whereas I want to define a new class with a dynamic name
28

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

2 Comments

Some of those examples use __import__, for newer code you can switch to importlib docs.python.org/dev/library/importlib.html . (py>=2.7 | >=3.1)
Don't use links, please provide a real description.
25

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)

1 Comment

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.
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.

4 Comments

Don't use eval as it is susceptible to security issues.
and how is it susceptible?
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.
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.
9

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.

2 Comments

Suppose that array comes from database. So this solution does not help.
well you just do type(cName)(**arguments)
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()

Comments

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/

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.