1

I am looking for a way to "identify" the class name on the fly based on an incoming parameter and create its object. The code which I attempted gives error "TypeError: 'str' object is not callable". Any suggestions on how to achieve this?

class interfaceMsg:
    def __init__(self):
        #Do some initializations


    def updateDB(self, cell_index, xml_msg):
        #Do something general


class interfaceMsg_myMsg(interfaceMsg):
    def __init__(self):
        interfaceMsg.__init__(self)
        #Do some specific initializations


class interfaceMsg_yourMsg(interfaceMsg):
    def __init__(self):
        interfaceMsg.__init__(self)
        #Do some special initializations

    def updateDB(self, cell_index, xml_msg):
        #Do something special



##and so on several derived classes



def doUpdateDB(cell_index, xml_msg):
    # I basically want to create an object on the fly and call its updateDB function

    #Create the class name correspoding to this message
    class_name = "interfaceMsg_" + xml_msg.attrib["showname"]

    #class_name becomes interfaceMsg_myMsg or interfaceMsg_yourMsg or interfaceMsg_xyzMsg

    #This gives TypeError: 'str' object is not callable
    obj = class_name()

    obj.updateDB(cell_index, xml_msg)

Thanks

2 Answers 2

0

what i do (for example in an engine of mine Contemplate), is this:

  1. have a set of classes available in subfolder
  2. dynamicaly import the appropriate class file
  3. get an instance of the class

All these assuming that the class is dynamic but from a specific set of available classes, sample code follows:

sample available class:

def __getClass__():

    class AClass:

        # constructor

        def __init__(self):
            pass

    return AClass



# allow to 'import *'  from this file as a module

__all__ = ['__getClass__']

sample dynamic class loading:

def include( filename, classname, doReload=False ):
    # http://www.php2python.com/wiki/function.include/
    # http://docs.python.org/dev/3.0/whatsnew/3.0.html
    # http://stackoverflow.com/questions/4821104/python-dynamic-instantiation-from-string-name-of-a-class-in-dynamically-imported

    #_locals_ = {'Contemplate': Contemplate}
    #_globals_ = {'Contemplate': Contemplate}
    #if 'execfile' in globals():
    #    # Python 2.x
    #    execfile(filename, _globals_, _locals_)
    #    return _locals_[classname]
    #else:
    #    # Python 3.x
    #    exec(Contemplate.read(filename), _globals_, _locals_)
    #    return _locals_[classname]

    # http://docs.python.org/2/library/imp.html
    # http://docs.python.org/2/library/functions.html#__import__
    # http://docs.python.org/3/library/functions.html#__import__
    # http://stackoverflow.com/questions/301134/dynamic-module-import-in-python
    # http://stackoverflow.com/questions/11108628/python-dynamic-from-import
    # also: http://code.activestate.com/recipes/473888-lazy-module-imports/
    # using import instead of execfile, usually takes advantage of Python cached compiled code

    global _G
    getClass = None
    directory = _G.cacheDir
    # add the dynamic import path to sys
    os.sys.path.append(directory)
    currentcwd = os.getcwd()
    os.chdir(directory)   # change working directory so we know import will work

    if os.path.exists(filename):

        modname = filename[:-3]  # remove .py extension
        mod = __import__(modname)
        if doReload: reload(mod) # Might be out of date
        # a trick in-order to pass the Contemplate super-class in a cross-module way
        getClass = getattr( mod, '__getClass__' )

    # restore current dir
    os.chdir(currentcwd)
    # remove the dynamic import path from sys
    del os.sys.path[-1]

    # return the Class if found
    if getClass:  return getClass()
    return None

This scheme enables these things:

  1. dynamic file and module/class loading, where classname/file is dynamic but class name might not correspond to filename (have a generic __getClass__ function for this in each module/class)

  2. the dynamic class file can be generated (as source code) on the fly or be pre-cached and so on... No need to (re-)generate if already available.

  3. Set of dynamic classes is specific and not ad-hoc, although it can be dynamicaly changed and/or enlarged at run-time if needed

Sign up to request clarification or add additional context in comments.

7 Comments

That seems a bit overcomplicated for the problem OP described; they seem to simply need globals instead of your homemade import system.
@l4mpi, i dont think so, but i'll let OP decide, i think this solution is more clean and generic, requiring only a scheme to load and identify classes, but one might like to do it differently. As a sidenote, for the use purpose (mentioned in start of answer), this was best solution
I don't doubt that there are use cases where something like this is needed, I'm just pretty certain that OPs situation isn't such a case.
Thanks Nikos M. That helped. Instead of following getClass approach, I noticed that getattr is able to return a class which can be used to instantiate the object. mod = __import__("my_module") class_name = getattr(mod, "myMsg_interfaceMsg") obj = class_name() That resolved my problem..gracefully
unfortunately, webpage says that I dont have enough "reputations" to vote..but thanks again Nikos M
|
-1

You're probably looking for globals, which is a dictionary of all global variables (that includes toplevel classes as well as imports):

from yourClasses import ClassA, ClassC

class ClassB(object): pass

def instantiate(className):
    cls = globals()[className] #find the class in the globals dict
    instance = cls()
    return instance

a_instance = instantiate("ClassA")

import random
random_instance = instantiate("Class"+random.choice("ABC"))

Or alternatively, build your own Dictionary of classes - that would be a cleaner choice, especially when dealing with user input.

myClasses = {"A": ClassA, "B": ClassB, "SomethingElseEntirely": ClassC}
clsName = raw_input("")
cls = myClasses[clsName]
instance = cls()

This is of course not limited to classes, you could also store and call methods in the same way.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.