[Python-ideas] "maybe import"?

Steven D'Aprano steve at pearwood.info
Fri Dec 27 05:08:09 CET 2013


On Fri, Dec 27, 2013 at 01:57:02AM +0000, Amber Yust wrote:
> It's a fairly standard pattern to see things like this:
> 
>     try:
>         import foo
>     except ImportError:
>         foo = None
> 
> (and of course, variants with from...import et cetera). These can
> potentially add a lot of clutter to the imports section of a file, given
> that it requires 4 lines to do a conditional import.

You can reduce that down to two lines:

    try:  import foo
    except ImportError:  foo = None


but your point is taken.

A more common pattern in my experience is:

try:
    import this
except ImportError:
    import that as this



> It seems like it'd be useful and clean to have a syntax that looked like
> this:
> 
>     maybe import foo
>     from bar maybe import baz
>     from qux maybe import quy as quz
> 
> Where the behavior would essentially be as above - attempt to run the
> import normally, and in cases where the import fails, map the name to a
> value of None instead. Users who want a different behavior are still free
> to use the long-form syntax. 

Hmmm. The basic idea makes a certain level of sense to me, but I'm not 
sure it makes enough sense to overcome the barrier required before 
adding a new keyword.

I'm not (yet) convinced of the need for this functionality, but if 
Python did gain this, I think I would prefer the colour of this 
bike-shed to be "perhaps import" rather than "maybe import". A couple of 
reasons:

- it seems to me that "maybe" is more likely to already be used in code
  than "perhaps", e.g. in three-value logics (true, false, maybe);

- to me, "maybe" feels somewhat random, arbitrary or indeterminant,
  whereas "perhaps" feels subtly more determinant. I can't justify this
  claim by dictionary definitions, perhaps it's just me :-)


If we're entertaining changes to imports, another possibility would be 
to allow fallback module names:

    import this or that or another as this

Each of "this", "that", "another" will be attempted, the first 
successful import being bound to the name "this". The "as this" part 
would be mandatory, so as to require a consistent name regardless of 
which module was imported. This would be a syntax error, since it isn't 
clear what name would be bound at the end:

    import this or that or another


This would also be allowed:

    from this or that or another import spam


With this syntax, we could add None as a special case:

    import this or that or another or None as this

would be equivalent to:

    module_names = ("this", "that", "another", "None")
    for name in module_names:
        if name == "None":
            spam = None
        else:
            try:
                this = __import__(name)
            except ImportError:
                continue
        break
    else:
        raise ImportError


and the "from...import" case could be written as:

    from this or that or None import spam


roughly equivalent to:

    module_names = ("this", "that", "another", "None")
    for name in module_names:
        if name == "None":
            spam = None
        else:
            try:
                temp = __import__(name)
                spam = temp.spam
            except ImportError:
                continue
        break
    else:
        raise ImportError


Advantages:

- covers both use-cases where you want to try a series of
  modules, and the one where you fall back to None;

- "or" is already a keyword, no new keywords needed;

- reads more like English;

- "import None" currently gives SyntaxError, so this
  can't interfere with modules actually called "None".


Disadvantages:

- more complexity to imports;

- only saves a few lines;

- this usage of "or" is not quite the same as the usage 
  as a boolean operator, e.g. different from "x in a or b".


> A possibly variant might be to also only run
> the import if the name isn't already bound, so that you could do something
> like...
> 
>     from frobber_a maybe import frob as frobber
>     from frobbler_b maybe import frobble as frobber
>     from frobber_c maybe import frobit as frobber
> 
> ...to potentially try different fallback options if the first choice for an
> interface provider isn't available.

I dislike this form, because it requires short-circuiting execution of 
separate lines. What would you expect this to do?

from frobber_a maybe import frob as frobber
frobber = 23
from frobbler_b maybe import frobble as frobber

Is the second maybe import attempted or not? I have no idea whether it 
should be or shouldn't be.


-- 
Steven


More information about the Python-ideas mailing list