Search code examples
pythondjangostringclassgetattr

Get class object from string


I'm writing the following to generate URLs for my urls.py:

urls = {
    'overview': {
        r'^$':          [ 'Index' ],
        r'^/account$':  [ 'Account' ],
    },

    'content': {
        r'^/content$':        [ 'Index' ]
        r'^/content/upload$': [ 'Uploader', 'Default' ]
    }

}

urlpatterns = patterns('')

for module, spec in urls.iteritems():
    urlpatterns += patterns('views.'+ module,
        [
                url(regex, (getattr(module.capitalize() , 'as_view'))(), action=view[0])
            if len(view) == 1 else
                url(regex, (getattr(view[0], 'as_view'))(), action=view[1])
            for regex, view in spec.iteritems()
        ]
    )

I have modules overview and content, with classes Overview, and Content and Uploader, respectively.

If the view array (e.g., [ 'Index' ] contains a single element, I use the capitalized form of the module (e.g., overview becomes Overview) to generate the route:

url(r'^$', Overview.as_view(), action='Index')

whereas if it contains two elements, (e.g., [ 'Uploader', 'Default' ]), the first element specifies the class name and the second the method:

url(r'^$', Uploader.as_view(), action='Default')

As you may have noticed, the issue is with my use of getattr(), whose first argument requires a class reference. So, my question is whether there is any way to get the class object from a string that contains the identifier of said class object, e.g., the Uploader class from 'Uploader'.

As a disclaimer these are not my exact routes, just an example. And of course further comments are welcome with respect to my overall design here as well.


Solution

  • I'd say there are two common ways of doing it. Consider example below:

    from random import choice
    
    
    class A(object):
        def __init__(self):
            self.name = 'in A'
    
    
    class B(object):
        def __init__(self):
            self.name = 'in B'
    
    
    class C(object):
        def __init__(self):
            self.name = 'in C'
    
    if __name__ == "__main__":
        classes = ['A', 'B', 'C']
        class_name = choice(classes)
        print class_name
    
        # 1st way
        obj = globals()[class_name]()
        print obj.name
    
        # 2nd way
        import sys
        obj = getattr(sys.modules['__main__'], class_name)()
        print obj.name
    
        # 3rd way - not recommended
        obj = eval(class_name)()
        print obj.name