4

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.

1 Answer 1

6

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

3 Comments

Ah, interesting. So, with respect to the second way, is it that getattr can operate on more than just classes/objects (namely, the __main__ module's "symbol table"), or is it that modules and classes are actually of the same nature? (Being that they both have 'attributes'). Thanks by the way!
Remember that everything in Python is an object, even the module ;)
Oh right, cool. So how have Python's language designers avoided a hefty performance penalty with such a thoroughly object-oriented approach? I suppose I can just look these things up at this point though..

Your Answer

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