# Conditional imports in one line using \`else\`

**URL:** <https://discuss.python.org/t/conditional-imports-in-one-line-using-else/972>\
**Category:** Ideas\
**Created:** [March 2, 2019, 11:10pm UTC](https://discuss.python.org/t/conditional-imports-in-one-line-using-else/972 "2019-03-02T23:10:43Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![gpshead](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/gpshead/32/54_2.png) [@gpshead](https://discuss.python.org/u/gpshead)\
**Post date:** [March 2, 2019, 11:10pm UTC](https://discuss.python.org/t/conditional-imports-in-one-line-using-else/972/1 "2019-03-02T23:10:43Z")

</div>

Conditional imports are somewhat common in code that supports multiple platforms, or code that supports additional functionality when some extra bonus modules are available. Today this is often written as:

```python
# pylint: disable=import-not-at-top
try:
  from monty.python.au import bruce
else:
  bruce = None

```

Four lines of code, plus a _potential_ linter directive asking tooling not to whine about logic before imports or non top level imports.

What if we could simply write any variant of the following:

```python
from monty.python.au import bruce else None
from monty.python.au import bruce else bruce = None
from monty.python.au import michael_baldwin as bruce else None
from monty.python.au import michael_baldwin as bruce else bruce = None
import michael_baldwin else None
import michael_baldwin else michael_baldwin = None
import michael_baldwin as bruce else bruce = None
import michael_baldwin as bruce else None
import monty.python.au else None # confusing...
import monty.python.au else monty = None # yuck

```

I’m using an `else` to convey the condition what to do on import failure instead of the try+except. I don’t really like that the name has to be repeated for the most natural reading but I dislike the way it reads without the `name = expr` to convey the conditional alternate name binding. I’d limit the `else` to only capturing `ImportError` though you could argue that it should be a broad except.

I’m also suggesting not supporting `else` on anything other than a simple single name import. `import long.dotted.name` could be ineligible for else because it feels awkward, though so long as the `else name = expr` syntax were chosen it’d still be comprehensible. Want to import multiple names from a package in a single import statement? I suggest not supporting `else` on that; though that should work fine via tuple assignment. having such things to not support is probably _more_ complicated.

things to avoid? I don’t _want_ anyone to write a conditional expression after the else. Or to allow anything other than simple `=` assignment if adopting that syntax (no augassign).

thoughts? a quick search didn’t turn this up as being proposed in the past but I didn’t look far.

unresolved thoughts. sometimes the alternate of a conditional import is a different import.

```python
import json else import simplejson as json

```

Include nested conditional import statements as part of this?

---

<div class="post-metadata">

**Author:** ![encukou](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/encukou/32/2461_2.png) [@encukou](https://discuss.python.org/u/encukou)\
**Post date:** [March 4, 2019, 10:24am UTC](https://discuss.python.org/t/conditional-imports-in-one-line-using-else/972/2 "2019-03-04T10:24:39Z")

</div>

A change like this should have heftier motivation than replacing four lines of code with one.  
A great example is PEP 380: `yield from` usually replaces just two lines, `for v in g: yield v`. If it was only that, it would have been rejected (at least under the old governance). The reason for adding `yield from` was that it _also_ solves [various more subtle problems](https://www.python.org/dev/peps/pep-0380/#formal-semantics). With then new command, the correct way to write it is also the most obvious – and that wasn’t true before.

I fear that’s not the case in your proposal. The `import ... else ...` doesn’t do anything more than the four lines it replaces. And it’s less flexible – the four lines can be trivially extended to things like:

- Handling other kinds of errors than ImportError
- Importing a fallback module instead (as you mentioned)
- Choosing a module based on a condition (if for some reason you need to look before you leap instead of preparing to ask for forgiveness)
- Having two optional modules, and importing either both or neither of them

If it’s the linter that bothers you, look into fixing your linter (and possibly into adjusting PEP 8 before that, to codify the right way to format conditional imports).

---

<div class="post-metadata">

**Author:** ![steven.daprano](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/steven.daprano/32/1083_2.png) [@steven.daprano](https://discuss.python.org/u/steven.daprano)\
**Post date:** [June 7, 2019, 12:42pm UTC](https://discuss.python.org/t/conditional-imports-in-one-line-using-else/972/3 "2019-06-07T12:42:20Z")

</div>

I like the idea of this syntactic sugar. Conditional imports are very common, especially when writing multi-version code.

One possibility I thought of a long time ago was to allow any number of module names separated by `or`, with the name to bind to mandatory:

```
import json or simplejson as json

```

Adding an optional `else` clause would be neat:

```
import json or simplejson as json else expression

```

which would be equivalent to:

```
try:
    import json as json
except:
    try:
        import simplejson as json
    except:
        json = expression

```

I expect that if this idea goes anywhere, there will be a huge amount of bike-shedding on the syntax and semantics 🙂 and a lot of opposition since it doesn’t really add anything _new_ to the language ☹ but I think its a nice bit of syntactic sugar which would improve readability a lot.

---

<div class="post-metadata">

**Author:** ![pf\_moore](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/pf_moore/32/35_2.png) [@pf\_moore](https://discuss.python.org/u/pf_moore)\
**Post date:** [June 7, 2019, 1:27pm UTC](https://discuss.python.org/t/conditional-imports-in-one-line-using-else/972/4 "2019-06-07T13:27:49Z")

</div>

> [@steven.daprano](#):
>
> a huge amount of bike-shedding

Obvious bikeshedding: `except:` or `except Exception:` or `except ImportError:`? 😄

The idea seems pretty convenient, and relatively innocuous. But I expect it’ll go nowhere, mainly because there simply isn’t _enough_ benefit to get people enthusiastic about it. One particular issue is that this sort of conditional import is typically needed by library authors rather than end users, and library authors are the least likely to be able to use the syntax (because of the need to support older versions of Python). That’s not to say we shouldn’t be investing in future improvements, just to reiterate that it’ll be hard to get much support for the idea.

Whether this counts as an unhealthy tendency towards stagnation, or a sensible counterbalance to overenthusiastic levels of change in a mature and widely used language, I honestly don’t know… 😉

---

<div class="post-metadata">

**Author:** ![pitrou](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/pitrou/32/28_2.png) [@pitrou](https://discuss.python.org/u/pitrou)\
**Post date:** [June 8, 2019, 11:29am UTC](https://discuss.python.org/t/conditional-imports-in-one-line-using-else/972/5 "2019-06-08T11:29:21Z")

</div>

I don’t know. Since optional imports are important to notice, I prefer to have the `try..except` block spelled out explicitly. Readability trumps concision here.

(but of course, now that we have the `:=` operator, that argument will be harder and harder to make :-/)

---

<div class="post-metadata">

**Author:** ![aeros](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/aeros/32/4140_2.png) [@aeros](https://discuss.python.org/u/aeros)\
**Post date:** [July 6, 2019, 9:07pm UTC](https://discuss.python.org/t/conditional-imports-in-one-line-using-else/972/6 "2019-07-06T21:07:15Z")

</div>

> [@steven.daprano](#):
>
> import json or simplejson as json

Personally, I’m quite fond of this syntax and the conditional approach to imports. Perhaps another alternative could be the ternary conditional syntax that Python already uses, but applied to the context of imports:

```auto
import json if json else simplejson as json 

```

I’m not certainly if this is intuitively clear, but in my opinion it looks quite clean and fits well with the general design style of Python.

> [@encukou](#):
>
> The `import ... else ...` doesn’t do anything more than the four lines it replaces

While this argument makes perfect sense from a purely functional perspective, there is an argument to be made from a design perspective. This is a contested area within the programing community in general, but exceptions usually are best suited to situations which are actually exceptional. If the developer wants to assess the existence of multiple modules and use them in an order or preference, this seems to be more suited to control flow in a conditional rather than an exception. It does seem to be somewhat counter-intuitive to rely on exceptions for determining import alternatives.

This ultimately comes down to design preference, but in general it is my opinion that exceptions should actually be exceptional. When control flow with conditionals can be utilized instead, they should be a preferable alternative. Especially in Python, language styling and design are incredibly important components to consider, even if there is no functional difference. When implemented correctly, syntactic sugar can significantly improve readability.
