0

I am porting code from Python 2 to 3. The Python 2 version uses this snippet to instantiate a class successfully:

#at this point, "module_name" is just a string
module = __import__(module_name, globals(), locals(), [])
#class_name is just a string
my_class = getattr(module, class_name)
class_instance = my_class()

In Python 3, that same code fails with an AttributeError, saying that my module name has no attribute of my class name. The other similar questions I've read here suggest that getattr should work for this task in Python 3, but it doesn't for me.

What am I misunderstanding? Is there a better way to instantiate a class from a string?

Bee
  • 195
  • 1
  • 3
  • 12
  • 4
    Not seeing anything obviously wrong here - is `module_name` a module, and `class_name` a string? We need a [MCVE]. – wim Oct 14 '19 at 22:59
  • Gotcha, I'll add some more in – Bee Oct 14 '19 at 23:02
  • 3
    Printing `dir(module)`, and then possibly some of the attributes that do actually exist, might give some hint as to what's going wrong. – jasonharper Oct 14 '19 at 23:11
  • One thing you're misunderstanding--just a semantic nitpick--which is not related to your problem. You're not "instantiating a class from a string". In your example the variable `my_class` is just a reference to the class itself. When you call `my_class()` you are just instantiating the class, period. This is why if you defined your class with `class A:`, say, you still get an instance of a class called `A` and not called `my_class`. It just happens when you use the `class` keyword it makes a class with the given name and assigns it to a variable with the same name as the class. – Iguananaut Oct 14 '19 at 23:13
  • What you're doing, rather, is looking a class up by name (given a string) in a module namespace. That's separate from the instantiation itself, or most likely even that it's a class. Try investigating directly in an interactive prompt. When you do `__import__(module_name)` check if it actually imported the module you expected. It's possible it doesn't. – Iguananaut Oct 14 '19 at 23:15
  • 2
    This use of `__import__` is gross and should be rewritten anyway. It's a hook meant for use by the interpreter itself, not by user code. Look to `importlib.import_module` instead. – wim Oct 14 '19 at 23:28
  • 1
    `getattr()` works just the same in Py2 and Py3. Either the module found by the import is not the one you expect (hint: add a `print(module)` after the import, you'll find out which module was _really_ imported), or the py3 version of this module doesn't define `class_name` anymore. And by all means, do what wim suggests: use `importlib.import_module`. – bruno desthuilliers Oct 15 '19 at 12:13
  • Thanks all, I tried out your suggestions and got it working now. Getting rid of `__import__` too. The problem was I had copied in my module to my conda environment's site-packages directory, but hadn't actually installed it, so `module.__file__` was returning null. – Bee Oct 15 '19 at 17:20

0 Answers0