0

So I have a somewhat long and growing list of classes in a script. At a certain point in the script I want to be able to test an arbitrary instance for its type, and then whatever that type is, I want to create a second object of the same type. I've tried researching this and I know I can accomplish this by storing every class in a dictionary, like so:

class Foo(object):
    pass
class Bar(object):
    pass
d = {"Foo": Foo, "Bar": Bar}
x = dict["Foo"]()

It does the trick, allowing me to use a variable or string containing the name of the class, in order to create an instance of the class. However, it requires that every time I create a new class I have to remember to also put a new entry in the dictionary--which isn't the worst thing in the world, but as they say, if you're doing the same task more than once you should make a computer do it.

Is there a better way? Can you somehow take a variable or string containing the name of a class, and without knowing what value the variable or string has, generate an instance of the class?

1
  • 1
    eval(classname + '()') or globals()[classname]() Commented Sep 24, 2015 at 5:07

3 Answers 3

3

So this is answering your problem rather than your question, but it seems you actually want to create another instance of an object rather than find a class by name. So that is even easier because you can find the class of an object with the type function. So to create a new instance b of the same type as a but with constructor parameters args simply do:

b = type(a)(args)
Sign up to request clarification or add additional context in comments.

1 Comment

Ah, that's makes great sense ... and actually does answer my question as well as my problem, although possibly I didn't phrase the question as clearly as I could have. But this is perfect, thank you.
3

All classes are in globals dictionary (dictionary containing the current scope's global variables). Get the dictionary with globals(), and then find it by name (string). As a result you will get a class, which can be instantiated with ().

class Foo(object):
    pass

x = globals()['Foo']()

Comments

0

Not sure why Huazuo Gao didn't make that an answer, but it solves my problem exactly and I've never seen that solution in my research on this problem--so I'll go ahead and punch it up as an answer.

You can do it using the string of the name of the class and the eval() function. So

class Foo(object):
    pass
a = Foo()
s = str(type(a))
# The string produced isn't quite the name of the class so it has to be stripped 
# of some surrounding characters.
m = s.find('.')
n1 = s.find("'")
n2 = s[n1+1:].find("'")
s = s[m+1:n1+n2+1]
b = eval(s + "()")

produces the desired behavior.

3 Comments

or >>> type(a).__name__ gives 'Foo'
@DanPatterson I'm not seeing how that does what I'm looking for. That seems to give the string name of a given class, whereas I'm looking to produce a class when I have the string name.
In retrospect I'm realizing the draw-back of the method given here, and this is perhaps why the commenter didn't turn this into an answer: The eval() function is extremely literal. You put string objects into it, and it runs those string arguments as commands, with little concern for the distinction between local and global variables (as far as I can tell). This had the consequence of creating a confusing bug in my application until I realized what was going on. The accepted answer avoids this problem.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.