Question

I'm new in programming so please don't kill me for asking stupid questions. I've been trying to understand all that class business in Python and I got to the point where could not find answer for my question just by google it.

In my program I need to call a class from within other class based on string returned by function. I found two solutions: one by using getattr() and second one by using globals() / locals().

Decided to go for second solution and got it working but I'm really don't understand how it's working.

So there is the code example:

class Test(object):
    def __init__(self):
        print "WORKS!"

room = globals()['Test'] 
room()

type(room()) gives:

<class '__main__.Test'>

type(room) gives:

<type 'type'> # What????

It looks like room() is a class object, but shouldn't that be room instead of room()?

Please help me because it is a little bit silly if I write a code which I don't understand myself.

Was it helpful?

Solution

What happens here is the following:

class Test(object):
    def __init__(self):
        print "WORKS!"

room = globals()['Test']

Here you got Test as room the way you wanted. Verify this:

room is Test

should give True.

type(room()) gives:

<class '__main__.Test'>

You do one step an go it backwards: room() returns the same as Test() would - an instance of that class. type() "undoes" this step resp. gets the type of the object - this is, of course, Test.

type(room) gives:

<type 'type'> # What????

Of course - it is the type of a (new style) class. The same as type(Test).


Be aware, however, that for

In my program I need to call a class from within other class based on string returned by function. I found two solutions: one by using getattr() and second one by using globals() / locals().

it could be better to create an explicitly separate dict. Here you have full control over which objects/classes/... are allowed in that context and which are not.

OTHER TIPS

First of all, I'd go with getattr instead.

In your example, room equals Test and is a class. Its type is type.

When you call room(), you instantiate Test, so room() evaluates to an instance of Test, whose type is Test.

Classes are objects too, in Python. All this does:

class Test(object):
    def __init__(self):
        print "WORKS!"

is create a class object and bind it to the name Test. Much as this:

x = []

creates a list object and binds it to the name x.

Test() isn't magic syntax for creating an instance. The Test is perfectly ordinary variable lookup, and the () is perfectly ordinary "call with empty arguments". It just so happens that calling a class will create an instance of that class.

If follows then that your problem of instantiating a class chosen based on having the name of the class as a string boils down to the much simpler problem of finding an object stored in a variable. It's exactly the same problem as getting that list bound to the name x, given the string "x". Once you've got a reference to the class in any old variable, you can simply call it to create your instance.

globals() returns a dictionary mapping the names of globals to their values. So globals()['Test'] will get you the class Test just as easily as globals()['x'] will get you the list. However it's usually not considered great style to use globals() like this; your module probably contains a large number of callables (including a bunch imported from other modules) that you don't want to be accidentally invoked if the function can be made to return their name. Given that classes are just ordinary objects, you can put them in a dictionary of your own making:

classes = {
    'Test': Test,
    'SomethingElse': Something,
    ...
}

This involves a bit more typing, but it's also easier to see what the intended usage is, and it gives you a bit more flexibility, since you can also easily pass this dictionary to other modules and have the instantiation take place elsewhere (you could do that with globals(), but then you're getting very weird).

Now, for the type(room) being type. Again, this is just a simple consequence of the fact that classes themselves are also objects. If a class is an object, then it should also be an instance of some class. What class is that? type, the "type of types". Much as any class defines the common behaviour of all its instances, the class type defines the common behaviour of all classes.

And just to make your brain hurt, type is an instance of itself (since type is also a class, and type is the class of classes). And it's a subclass of object (since all type instances are object instances, but not all object instances are type instances), and also an instance of object (since object is the root class of which everything is an instance).

You can generally ignore type as an advanced topic, however. :)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top