1

I'm currently refactoring a Python 2 project which includes the ability to add or remove plugins, which are Python modules implementing a given API.

The main app accesses add/remove/update hooks in plugins by calling e.g. __import__('plugin_name').hook_add() after pulling plugin names from a database, but this seems like a hacky approach. Having said that, I don't know of better ways to programatically access plugins.

Is this considered an antipattern in Python?

asked May 17, 2016 at 12:44
1
  • 1
    There's nothing inherently wrong with __import__. You could possibly use the importlib module instead, but it isn't necessarily a better alternative. If you think it is a hacky approach, maybe you can try to design a better solution and see if it is clearer and easier to understand than the current code. Commented May 17, 2016 at 12:49

1 Answer 1

3

Is using __import__('module_name') an antipattern in Python?

The api for __import__ is somewhat misleading. I personally would prefer to avoid it where possible.

The docs for Python 3 state:

Direct use of __import__() is also discouraged in favor of importlib.import_module().

Here's the API for __import__:

mod = __import__(
 module, # string of dotted name
 globals=None, # only needed to do relative import
 locals=None, # implementation ignores this
 fromlist=()) # fromlist just needs to be non-empty... :(
 level=0 # relative import, not going into this part
 )

If fromlist is empty, you import the module, but get returned the root package like this, so you have to do the dotted lookup to get back to it:

>>> foo = __import__('foo.bar.baz')
>>> foo.bar.baz
<module 'foo.bar.baz' from /.../foo/bar/baz.py>

This is the same as

>>> import foo.bar.baz
>>> foo.bar.baz
<module 'foo.bar.baz' from /.../foo/bar/baz.py>

If you just want the module, you need fromlist to be non-empty:

>>> baz = __import__('foo.bar.baz', fromlist=[None])
>>> baz
<module 'foo.bar.baz' from /.../foo/bar/baz.py>

Which is the same as

>>> from foo.bar import baz
>>> baz
<module 'foo.bar.baz' from /.../foo/bar/baz.py>
>>> baz is foo.bar.baz
True

Use importlib.import_module instead:

Here's the usage for import_module:

>>> from importlib import import_module
>>> baz = import_module('foo.bar.baz')

That's much nicer.

answered May 18, 2016 at 15:51

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.