11

When attempting to import from an alias - which is common in scala I was surprised to see the following results:

Create an alias

  import numpy as np

Use the alias to import modules it contains

  from np import linalg

  ImportError: No module named np.linalg

Is there any other syntax/equivalent in python useful for importing modules?

WestCoastProjects
  • 58,982
  • 91
  • 316
  • 560

2 Answers2

31

Using import module as name does not create an alias. You misunderstood the import system.

Importing does two things:

  1. Load the module into memory and store the result in sys.modules. This is done once only; subsequent imports re-use the already loaded module object.
  2. Bind one or more names in your current namespace.

The as name syntax lets you control the name in the last step.

For the from module import name syntax, you need to still name the full module, as module is looked up in sys.modules. If you really want to have an alias for this, you would have to add extra references there:

import numpy  # loads sys.modules['numpy']
import sys

sys.modules['np'] = numpy  # creates another reference

However, doing so can have side effects when you also are importing submodules. Generally speaking, you don't want to create aliases for packages by poking about in sys.modules without also creating aliases for all (possible) submodules as not doing so can cause Python to re-import submodules as separate namespaces.

In this specific case, importing numpy also triggers the loading of numpy.linalg, so all you really have to do is:

import numpy as np
# np.linalg now is available

No module aliasing is needed. For packages that don't import submodules automatically, you'd have to use:

import package as alias
import package.submodule

and alias.submodule is then available anyway, because a submodule is always added as an attribute on the parent package.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • thx Martijn i get `NameError: name 'numpy' is not defined` : can you verify that snippet? Ah ok I had already done `import numpy as np` so i needed `sys.modules['np'] = np` – WestCoastProjects Feb 25 '17 at 18:33
  • @javadba: did you actually run `import numpy` as shown? – Martijn Pieters Feb 25 '17 at 18:33
  • this works well - gotta wait few mins to award – WestCoastProjects Feb 25 '17 at 18:36
  • 2
    It's a bit of an overstatement to say that it "doesn't create an alias". It does create an alias. But what it creates an alias for is a module object, not an import path (so you can't import from it). – BrenBarn Feb 25 '17 at 23:08
  • _"for packages that don't import submodules automatically"_ *aha* ! The inconsistent behavior on availability of submodules was confusing me. I am reading this as "they may or may not already be imported" and "it's up to the package developer". I wonder is there a commonly accepted/de-facto approach or guideline on whether submodules are auto imported or not? – WestCoastProjects Jun 10 '19 at 17:38
  • @javadba There is only: pre-import if that makes your API easier to use. But mostly it'll be a side-effect, because some other code (in that project itself, more often than not) depends on that submodule and has already imported it. – Martijn Pieters Jun 11 '19 at 13:50
  • Adding aliases to `sys.modules` is a really dangerous idea, because it can cause unexpected submodule reloading. If you do `import module; from module import submodule as a; sys.modules['m'] = module; from m import submodule as b`, now your modules are in an inconsistent state where there are two versions of `module.submodule` running around, including two versions of all classes defined in that submodule. – user2357112 Oct 15 '19 at 09:35
  • This causes real bugs with, say, [exception handling](https://stackoverflow.com/questions/46715586/isinstance-unexpectedly-returning-false), because you're trying to catch a `urllib3.exceptions.HTTPError`, and your error message says the exception is a `urllib3.exceptions.HTTPError`, but it won't trigger your `except` because you've actually got two versions of the exception class. (That particular case got *mostly* suppressed by adding even more aliases, but they've still got a problem waiting to happen if any submodules aren't loaded yet when they hunt for aliases to set.) – user2357112 Oct 15 '19 at 09:41
  • @user2357112: that's... a rather obscure aliasing issue, however. Plenty of projects use aliasing to handle backwards-compatibility issues without running into that issue. If you must alias a *package*, then just aliases for all transitive subpackages up front to prevent that. I know that this isn't a viable solution for the `requests.packages` alias, they should be following the [`six` module alias approach](https://github.com/benjaminp/six/blob/aa4e90bcd7b7bc13a71dfaebcb2021f4caaa8432/six.py#L103-L124) for that, really. – Martijn Pieters Oct 15 '19 at 11:56
  • @user2357112: This specific answer focuses on setting straight a misconception of the `[from ...] import .. as ...` syntax, the whole `sys.modules` aliasing mention doesn't need in-depth coverage of how to do this correctly with packages. – Martijn Pieters Oct 15 '19 at 12:01
  • NumPy *is* a package, but you're not adding submodule aliases. This breaks things like [equality](http://ideone.com/EGi4Ey) and [addition](http://ideone.com/tXDdY9) of `numpy.polynomial.Polynomial` instances. (Also, making sure you have all submodules handled is hard to do in general, with issues like trying to distinguish a submodule that hasn't been loaded from a file that isn't actually supposed to be imported, like test scripts and setup scripts.) – user2357112 Oct 16 '19 at 01:06
  • I argue that this answer is better without the mention of `sys.modules` aliases. Doing them right is a lot more subtle than it seems, and a lot more subtle than this answer explains. I think an answer that leaves them out entirely will lead readers to write better code than an answer that mentions them without mentioning the issues they can cause, and while the answer could be expanded with a full explanation of the safety issues and mitigations available, I think that would hurt the answer's focus compared to just taking out the `sys.modules` alias stuff entirely. – user2357112 Oct 16 '19 at 01:12
  • @user2357112: Now that I'm not reading this on a small mobile screen, I can easily see that I do appear to be advocating that `sys.modules['np'] = ...` is something you'd want to do. I added a warning against that. – Martijn Pieters Oct 16 '19 at 10:19
1

My understanding of your example would be that since you already imported numpy, you couldn't re import it with an alias, as it would already have the linalg portion imported.