Python dynamic class names

Trying to instantiate a class based on a string value and ... fail. The parser object below is a dict , in the example, let's say we have one called foo , and here parser['name'] is 'foo':

 obj = parser['name']() 

Failed to get TypeError: 'str' object is not callable . But, since I have:

 class foo: def __init__(self(): print 'Hello' 

And if I do obj = foo() , it works fine and creates the correct object. Also, calling obj = type(parser['name'])() does not work.

How to resolve this? Update: I really do not want to use a matching system: the names of these classes are determined by INI files and parsed in this way, so they will be strings.

+5
python
source share
8 answers
 classmap = { 'foo': foo } obj = classmap[parser['name']]() 
+11
source share

As indicated in:
Dynamic Python class names

There is an easier way to do this if you know in which module the classes are defined, for example:

 getattr(my_module, my_class_name)() 
+9
source share

Do not use the lines:

 parser = {} class foo: pass parser['foo'] = foo obj = parser['foo']() 
+5
source share

The built-in function type(name, bases, dict) is the right way to dynamically build classes - especially with given strings for class names. See the documentation here: http://docs.python.org/library/functions.html#type

In your specific example, this might look like this:

 >>> def init(self): ... print 'Hello' ... >>> Foo = type('Foo', (object,), {'__init__': init}) >>> foo = Foo() Hello 
+2
source share

You can use a metaclass that stores the specification of known classes:

 # a metaclass class Registry(type): # store all the types we know registered = {} def __new__(cls, name, bases, attrs): # create the new type newtype = super(Registry, cls).__new__(cls, name, bases, attrs) # store it cls.registered[name] = newtype return newtype @classmethod def class_by_name(cls, name): # get a class from the registerd classes return cls.registered[name] # arbitrary base class for every class that should be in the Register class Registered(object): __metaclass__ = Registry # some classes class Foo(Registered): pass class Bar(Foo): pass # get the class object: print Registry.class_by_name('Foo') # <class '__main__.Foo'> # it can be instanciated too ofc: print Registry.class_by_name('Bar')() # <__main__.Bar object at 0x01F0F9F0> 

But not everyone understands metaclasses, so you can avoid them to prevent confusion. They may be useful for such things, but as you can see from other answers, there are many other ways to do this.

+2
source share

You can use validation to create a class map:

 def get_classes(): classes = {} for name, obj in inspect.getmembers(sys.modules[__name__]): if inspect.isclass(obj): classes[name] = obj return classes 

Then create an instance of the class

 >>> classes = get_classes() >>> c = classes['ClassName'] >>> c <class ClassName...> 

For the most part, using how can I get a list of all the classes in the current module in Python?

+2
source share

In response to your update: the only way to do this is through a matching system. If you do not want to use an explicit mapping system, then you can use one of the built-in Python mapping systems, although, in my opinion, it is less clear and clear.

 obj = globals()[parser['name']]() 

will access a global object named parser['name'] == 'foo' . If this is a class (or the class that you really want to create based on user input), then you should be good to go. Otherwise, you will have to build logic around it in order to whitelist those classes that you really want.

If classes come from a module, you can use this __dict__ attribute for the same effect.

 obj = somemodule.__dict__[parser['name']]() 

The same warnings apply to this situation as the previous one. Better to just use explicit mapping

-one
source share

I would use a class name map for a class object, as everyone else says. You can initialize it with statements like parser[foo.__name__] = foo . If you do not want to use the mapping object, you will have to revert to using the eval function, as shown below:

 >>> class foo: ... pass ... >>> klass_name = 'foo' >>> klass_inst = eval(klass_name) >>> klass_inst <class __main__.foo at 0x1004b2b90> >>> inst = klass_inst() >>> inst <__main__.foo instance at 0x1004d2680> >>> 

Of course, if you want to use the classes built into the package, the package will need to be imported before you perform eval . You really need to create a mapping object so that you can restrict the classes that can be accessed using this code.

-4
source share

All Articles