
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. 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. 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.

On Thu, Dec 26, 2013 at 5:57 PM, Amber Yust <amber.yust@gmail.com> wrote:
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. A possibly variant might be to also only run the import if the name isn't already bound,
I think you mean do the import if the name is unbound *or bound to None.* Otherwise, it doesn't work in the example you gave. Here's another use case. Some modules, e.g., pycrypto need to be compiled in order to be installed. I have a stub version of pycrypto which can be used as a substitute for testing without actually encrypting anything. Rather than using a new keyword, the try keyword would fit here fine: try import Crypto try import CryptoStub as Crypto note that there are cases where this can't be a drop in replacement: try import Crypto.Random try import CryptoStub.Random as Crypto.Random # not allowed you'd have to instead write: try import Crypto.Random as CryptoRandom try import CryptoStub.Random as CryptoRandom --- Bruce

On Thu Dec 26 2013 at 7:40:19 PM, Bruce Leban <bruce@leapyear.org> wrote:
I think you mean do the import if the name is unbound *or bound to None.* Otherwise, it doesn't work in the example you gave.
Yes, that is what I meant, sorry. Another option would be "not bound to something that is not a module" - but I think "unbound or None" is probably the most versatile option. On Thu Dec 26 2013 at 8:08:45 PM, Steven D'Aprano <steve@pearwood.info> wrote:
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".
Another option would be to re-use the 'or' keyword: from foo import bar or None Where the bit after the 'or' simply specifies a default value to assign if an ImportError occurs.

In fact, reuse of the 'or' keyword also leads to these nice options: import foo or None as bar from foo import bar or None as baz On Thu Dec 26 2013 at 8:36:24 PM, Amber Yust <amber.yust@gmail.com> wrote:
On Thu Dec 26 2013 at 7:40:19 PM, Bruce Leban <bruce@leapyear.org> wrote:
I think you mean do the import if the name is unbound *or bound to None.* Otherwise, it doesn't work in the example you gave.
Yes, that is what I meant, sorry. Another option would be "not bound to something that is not a module" - but I think "unbound or None" is probably the most versatile option.
On Thu Dec 26 2013 at 8:08:45 PM, Steven D'Aprano <steve@pearwood.info> wrote:
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".
Another option would be to re-use the 'or' keyword:
from foo import bar or None
Where the bit after the 'or' simply specifies a default value to assign if an ImportError occurs.

I like that. I usually end up doing that with ElementTree: try: from xml.etree import cElementTree as etree except: try: from lxml import etree except: from xml.etree import ElementTree as etree It would all be: import xml.etree.cElementTree or lxml.etree or xml.etree.ElementTree as etree On Thu, Dec 26, 2013 at 10:36 PM, Amber Yust <amber.yust@gmail.com> wrote:
On Thu Dec 26 2013 at 7:40:19 PM, Bruce Leban <bruce@leapyear.org> wrote:
I think you mean do the import if the name is unbound *or bound to None.* Otherwise, it doesn't work in the example you gave.
Yes, that is what I meant, sorry. Another option would be "not bound to something that is not a module" - but I think "unbound or None" is probably the most versatile option.
On Thu Dec 26 2013 at 8:08:45 PM, Steven D'Aprano <steve@pearwood.info> wrote:
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".
Another option would be to re-use the 'or' keyword:
from foo import bar or None
Where the bit after the 'or' simply specifies a default value to assign if an ImportError occurs.
_______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
-- Ryan When your hammer is C++, everything begins to look like a thumb.

On Dec 27, 2013, at 9:43, Ryan Gonzalez <rymg19@gmail.com> wrote:
I like that. I usually end up doing that with ElementTree:
try: from xml.etree import cElementTree as etree
Python 3 has already fixed that. You just import ElementTree and you get the C-accelerated version. And the same is true for cPickle, etc. A new language feature that offers a different way to solve something that's already been solved better doesn't seem very useful. Of course I do write stuff like this when I'm trying to write code that works with 2.6+/3.2+, but a new language feature that's a syntax error in 2.x wouldn't help there either.
except: try: from lxml import etree except: from xml.etree import ElementTree as etree
It would all be:
import xml.etree.cElementTree or lxml.etree or xml.etree.ElementTree as etree
On Thu, Dec 26, 2013 at 10:36 PM, Amber Yust <amber.yust@gmail.com> wrote:
On Thu Dec 26 2013 at 7:40:19 PM, Bruce Leban <bruce@leapyear.org> wrote:
I think you mean do the import if the name is unbound or bound to None. Otherwise, it doesn't work in the example you gave.
Yes, that is what I meant, sorry. Another option would be "not bound to something that is not a module" - but I think "unbound or None" is probably the most versatile option.
On Thu Dec 26 2013 at 8:08:45 PM, Steven D'Aprano <steve@pearwood.info> wrote:
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".
Another option would be to re-use the 'or' keyword:
from foo import bar or None
Where the bit after the 'or' simply specifies a default value to assign if an ImportError occurs.
_______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
-- Ryan When your hammer is C++, everything begins to look like a thumb. _______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/

On Fri, Dec 27, 2013 at 12:59:48PM -0800, Andrew Barnert wrote:
On Dec 27, 2013, at 9:43, Ryan Gonzalez <rymg19@gmail.com> wrote:
I like that. I usually end up doing that with ElementTree:
try: from xml.etree import cElementTree as etree
Python 3 has already fixed that. You just import ElementTree and you get the C-accelerated version.
And the same is true for cPickle, etc.
Not if the C-accelerated version isn't available. Or perhaps there are two pure-Python modules with the same API, and you're not sure which is installed. This issue is bigger than just C-accelerators in the CPython standard library. It applies any time you have two or more alternatives with the same API, a preferred module and an fallback module. E.g. readline in the stdlib, versus pyreadline, a third-party Windows port. A point against this suggestion: the best syntactic sugar opens up new and successful idioms. List comps and decorators have been great successes. Being able to embed a list comp as an expression, instead of a for-loop as a statement, is a great win. This new syntax doesn't open up new idioms for writing code. It is purely sugar, and as such, it isn't such a compelling feature. On the other hand, I think it does simplify a very common use-case. I often use fallback modules with the same API, and if only this new syntax had been introduced back in Python 2.4 or 2.5 I would be using it all the time now. Unfortunately, most (but not all) of my code has to support 2.4 or 2.5, or at least 3.3, so the usefulness of new syntax is severely limited *right now*. But if this syntax were introduced into Python 3.5 (its surely too late for 3.4) I reckon I would be able to use it around Python 3.6 or 3.7. And of course those who won't need to support versions of Python prior to 3.5 could use it straight away. So don't think of this as something you are going to use. Think of this as an investment for future Python users who are starting with 3.5 and don't care about backwards compatibility with Python 3.3 and 3.4 (let alone older versions). On that basis, I'm going to vote: +1 on "import preferred or fallback as name". +0 on allowing "import module or None", to cover the idiom: try: import module except ImportError: module = None which may not be encouraged, but it is occasionally useful. -0 on "from preferred or fallback import name", simply because I'm not sure how to extend it to multiple names, so I'd rather leave it out. -1 on Amber's original suggestion "maybe import name", as the benefit is too little to justify introducing a new keyword. -- Steven

On 28 December 2013 22:27, Steven D'Aprano <steve@pearwood.info> wrote:
So don't think of this as something you are going to use. Think of this as an investment for future Python users who are starting with 3.5 and don't care about backwards compatibility with Python 3.3 and 3.4 (let alone older versions).
On that basis, I'm going to vote:
+1 on "import preferred or fallback as name".
+0 on allowing "import module or None", to cover the idiom:
try: import module except ImportError: module = None
which may not be encouraged, but it is occasionally useful.
-0 on "from preferred or fallback import name", simply because I'm not sure how to extend it to multiple names, so I'd rather leave it out.
-1 on Amber's original suggestion "maybe import name", as the benefit is too little to justify introducing a new keyword.
I used to be a fan of the "or" based variants, but I eventually went off the idea. My reasoning went as follows: 1. For a single file script, you're only doing the import once, so there's no repetition, and hence little to be gained from the more concise syntax (and the cost of a new thing for readers to learn) 2. For a multi file package or application, it's trivial to factor out the compatibility checking to a helper module, so there's *still* no need for repetition. A compatibility module also lets you build an adaptation layer if the APIs aren't *quite* the same (for example, RHEL5 has the ancient pre-simplejson JSON module, so naive "import json" code will mistakenly think it has the 2.6+ stdlib version - a helper module can detect oddball discrepancies like that one and work around them, but naive syntax would do the wrong thing if a similar situation arose again in the future). Essentially, the niche that the syntax variants can cover is too small to be worth making the already horrendously complex import statement syntax and semantics even *more* complicated, when you can either spell it out explicitly in the single file case, or use a helper module to centralise the selection logic in the multiple file case. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

On Dec 28, 2013, at 4:27, Steven D'Aprano <steve@pearwood.info> wrote:
On Fri, Dec 27, 2013 at 12:59:48PM -0800, Andrew Barnert wrote:
On Dec 27, 2013, at 9:43, Ryan Gonzalez <rymg19@gmail.com> wrote:
I like that. I usually end up doing that with ElementTree:
try: from xml.etree import cElementTree as etree
Python 3 has already fixed that. You just import ElementTree and you get the C-accelerated version.
And the same is true for cPickle, etc.
Not if the C-accelerated version isn't available.
Right, in which case you get the pure Python version--exactly as if you'd done the try/import/except/import, or used this proposed new feature. So there is no advantage to doing the more complicated thing, except 2.x compatibility--which you obviously wouldn't get with a new language feature.
Or perhaps there are two pure-Python modules with the same API, and you're not sure which is installed. This issue is bigger than just C-accelerators in the CPython standard library. It applies any time you have two or more alternatives with the same API, a preferred module and an fallback module. E.g. readline in the stdlib, versus pyreadline, a third-party Windows port.
There are maybe three such examples that people use regularly. Is that enough to warrant a change in the language? Well, that's not quite true. It's very common for modules that were renamed in 3.0, or that were recently added but have backward compat ports on PyPI. But again, a language change won't help those cases anyway. Unless you're expecting another mass renaming in 4.0?

On Sat, Dec 28, 2013 at 11:55:19AM -0800, Andrew Barnert wrote:
On Dec 28, 2013, at 4:27, Steven D'Aprano <steve@pearwood.info> wrote:
Or perhaps there are two pure-Python modules with the same API, and you're not sure which is installed. This issue is bigger than just C-accelerators in the CPython standard library. It applies any time you have two or more alternatives with the same API, a preferred module and an fallback module. E.g. readline in the stdlib, versus pyreadline, a third-party Windows port.
There are maybe three such examples that people use regularly. Is that enough to warrant a change in the language?
There's only one *common* example of augmented assignment, x += 1, but that was enough to justify a whole raft of new syntax, += -= *= |= etc because the *idiom* of "x = x op arg" is common. What matters is not the specific examples of which modules get used in this way, but that the idiom of try: import this except ImportError: import that as this is common, not the specific values of this/that. I do not expect that the idiom of having a fallback module when the preferred module isn't available will ever disappear, simply because there are too many circumstances in which it comes up. Having said that, Nick's comments strike me as critical. "import this or that" doesn't buy us anything that can't already be solved in other ways. If it were easy to add, then perhaps it would be justified. But the implementation of import is already gnarly and hard to maintain (so I'm told), so adding more complexity to it for something which is purely syntactic sugar is probably not the best thing to do. Maybe in Python 4000 :-) -- Steven

On 29 Dec 2013 09:44, "Steven D'Aprano" <steve@pearwood.info> wrote:
On Sat, Dec 28, 2013 at 11:55:19AM -0800, Andrew Barnert wrote:
On Dec 28, 2013, at 4:27, Steven D'Aprano <steve@pearwood.info> wrote:
Or perhaps there are two pure-Python modules with the same API, and you're not sure which
is
installed. This issue is bigger than just C-accelerators in the CPython standard library. It applies any time you have two or more alternatives with the same API, a preferred module and an fallback module. E.g. readline in the stdlib, versus pyreadline, a third-party Windows port.
There are maybe three such examples that people use regularly. Is that enough to warrant a change in the language?
There's only one *common* example of augmented assignment, x += 1, but that was enough to justify a whole raft of new syntax, += -= *= |= etc because the *idiom* of "x = x op arg" is common.
What matters is not the specific examples of which modules get used in this way, but that the idiom of
try: import this except ImportError: import that as this
is common, not the specific values of this/that. I do not expect that the idiom of having a fallback module when the preferred module isn't available will ever disappear, simply because there are too many circumstances in which it comes up.
Having said that, Nick's comments strike me as critical. "import this or that" doesn't buy us anything that can't already be solved in other ways. If it were easy to add, then perhaps it would be justified. But the implementation of import is already gnarly and hard to maintain (so I'm told), so adding more complexity to it for something which is purely syntactic sugar is probably not the best thing to do.
I suspect this would actually be pretty easy to implement (for a given definition of easy, since we'd likely handle it in the bytecode generation phase). However, it would still make the import statement even harder to fully comprehend than it already is, which is actually quite a notable achievement :) Cheers, Nick.
Maybe in Python 4000 :-)
-- Steven _______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/

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

On 12/27/2013 05:08 AM, Steven D'Aprano wrote:
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.
Same for me. In fact, while the use case is clear and common, I'm not sure syntax it's worth dedicated syntax at all, especially because this happens once in a module and at a definite place (import section).
[...]
If we're entertaining changes to imports, another possibility would be to allow fallback module names:
import this or that or another as this
I like that form.
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
Right.
This would also be allowed:
from this or that or another import spam
We'd also, or rather, need: from this import foo or that import bar or another import baz as spam which starts to be a bit complicated... Maybe (or perhaps) with parens: from ((this import foo) or (that import bar) or (another import baz)) as spam ?
With this syntax, we could add None as a special case:
import this or that or another or None as this
Yep!
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
Seems correct, expected semantics.
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
Right.
Advantages:
- covers both use-cases where you want to try a series of modules, and the one where you fall back to None;
Plus, as shown above we need to cover the case were a imported element have various names in original module. (Either all cases are covered, or it's definitely not worth bothering, imo.)
- "or" is already a keyword, no new keywords needed;
- reads more like English;
Not clearer than "maybe", in my ears (sic!) but I'm not english native speaker.
- "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".
Yes, it's more like prioritized choice in parsing (an operand in either a symbol or a real or an int), which is at times termed 'or' as well. Denis

On Sun, Dec 29, 2013 at 1:59 AM, spir <denis.spir@gmail.com> wrote:
This would also be allowed:
from this or that or another import spam
We'd also, or rather, need:
from this import foo or that import bar or another import baz as spam
which starts to be a bit complicated... Maybe (or perhaps) with parens:
from ((this import foo) or (that import bar) or (another import baz)) as spam
Can't say I like that variant - getting complicated and hard to read, even with parens. If you're importing different names from different modules, it's going to get very long, and then people are going to want to split it across lines, and then the obvious question is: what's been gained over the try/except variant? There is one thing, though, that I'm seeing of all this. Exception throwing is asymmetrical: you can attempt a series of statements until one fails, but there's no convenient syntax to attempt a series of statements until one succeeds. I wonder, could the more general case be solved? Is there a way to, without stupid stuff like eval, wrap up a few statements so they can be executed in a loop: def import_any(statement_list): for try_me in statement_list: try: # uhh, this is the bit I'm not sure about... try_me() # this would work if they're functions instead! return except ImportError: pass raise ImportError This works for a set of functions, but not for a bunch of "from this import that" statements. Would it be worth mangling the top of your script until it can be done with importlib or __import__? Doesn't seem nearly as clean, somehow. ChrisA

I'm fairly convinced by the "too small" reasoning (summed up well by Nick). I could potentially see a small and not incredibly intrusive improvement of allowing imports from a tuple-style group of alternatives being useful for things like c-accelerators, e.g... import (accelerated_foo, alternative_foo) as foo from (accelerated_foo, alternative_foo) import bar But that would be a "nice to have" thing rather than a big difference. On Sat Dec 28 2013 at 8:10:47 AM, Chris Angelico <rosuav@gmail.com> wrote:
On Sun, Dec 29, 2013 at 1:59 AM, spir <denis.spir@gmail.com> wrote:
This would also be allowed:
from this or that or another import spam
We'd also, or rather, need:
from this import foo or that import bar or another import baz as spam
which starts to be a bit complicated... Maybe (or perhaps) with parens:
from ((this import foo) or (that import bar) or (another import baz)) as spam
Can't say I like that variant - getting complicated and hard to read, even with parens. If you're importing different names from different modules, it's going to get very long, and then people are going to want to split it across lines, and then the obvious question is: what's been gained over the try/except variant?
There is one thing, though, that I'm seeing of all this. Exception throwing is asymmetrical: you can attempt a series of statements until one fails, but there's no convenient syntax to attempt a series of statements until one succeeds. I wonder, could the more general case be solved? Is there a way to, without stupid stuff like eval, wrap up a few statements so they can be executed in a loop:
def import_any(statement_list): for try_me in statement_list: try: # uhh, this is the bit I'm not sure about... try_me() # this would work if they're functions instead! return except ImportError: pass raise ImportError
This works for a set of functions, but not for a bunch of "from this import that" statements. Would it be worth mangling the top of your script until it can be done with importlib or __import__? Doesn't seem nearly as clean, somehow.
ChrisA _______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/

On Dec 28, 2013, at 8:10, Chris Angelico <rosuav@gmail.com> wrote:
There is one thing, though, that I'm seeing of all this. Exception throwing is asymmetrical: you can attempt a series of statements until one fails, but there's no convenient syntax to attempt a series of statements until one succeeds. I wonder, could the more general case be solved? Is there a way to, without stupid stuff like eval, wrap up a few statements so they can be executed in a loop:
def import_any(statement_list): for try_me in statement_list: try: # uhh, this is the bit I'm not sure about... try_me() # this would work if they're functions instead! return except ImportError: pass raise ImportError
This works for a set of functions, but not for a bunch of "from this import that" statements. Would it be worth mangling the top of your script until it can be done with importlib or __import__? Doesn't seem nearly as clean, somehow.
This is a clever idea. If you could work out a clean syntax for the "try until one works" syntax, it would solve a wider range of problems than just this import issue. It strikes me that there's some similarity with if/elif/else. Maybe just: try: stuff except try: other stuff except try: different stuff except Exception as e: deal with it But there are a lot of open questions. First, "except try" looks horrible, but I can't think of anything better. If they all fail, do you only get the last exception, or are they all chained together? Would there be a use for a sequence like this without except on the end (so if they all fail, it just raises)? Can you put an exception type or tuple between the "except try"? What about an as clause (so the block could use it)?

On Sat, Dec 28, 2013 at 12:05 PM, Andrew Barnert <abarnert@yahoo.com> wrote:
Would there be a use for a sequence like this without except on the end (so if they all fail, it just raises)?
I think what you're talking about is just leaving the try off the last clause (as in the example below).
Can you put an exception type or tuple between the "except try"? What about an as clause (so the block could use it)?
I started writing a mail with exactly this subject line and discarded it because of the latter two issues. In code I've recently written I have a chain of three and while the indentation is ugly, it's not so ugly that it cries out as a must fix language feature. And the problem is that I really want to limit to specific exceptions. In one case I have something like this: try: .... except KeyError: try: .... except AttributeError: try: .... except IndexError: .... and if I can't specify the specific exception, this is not helpful. On the other hand try: .... except KeyError try: .... except AttributeError try: .... except IndexError: .... only really saves me two colons and some whitespace. If the language had this feature, I'd use it, but that doesn't make it worth adding. --- Bruce

On Dec 28, 2013, at 20:39, Bruce Leban <bruce@leapyear.org> wrote:
On Sat, Dec 28, 2013 at 12:05 PM, Andrew Barnert <abarnert@yahoo.com> wrote:
Can you put an exception type or tuple between the "except try"? What about an as clause (so the block could use it)?
I started writing a mail with exactly this subject line and discarded it because of the latter two issues.
The second one is pretty minor; it's just a matter of making the syntax clean, and I'm sure someone would come up with something if it were worth doing. The part that worries me about the first issue is that there seem to be two reasonable ways to read it. In your example below, if the first attempt raises an AttributeError, should it go to the "except AttributeError try:" block, or should that only happen if the second attempt raises one? The first variation means it's _not_ just syntactic sugar for the overly indented form you gave before it. But that also means (I think) it requires a change to the way exceptions are handled. (I'd have to sit down and work out the bytecode to be sure about that.) And, more importantly, I don't think the meaning would be obvious to a reader--the fact that you assumed the other meaning was the only one possible is pretty strong evidence for that.
In code I've recently written I have a chain of three and while the indentation is ugly, it's not so ugly that it cries out as a must fix language feature. And the problem is that I really want to limit to specific exceptions. In one case I have something like this:
try: .... except KeyError: try: .... except AttributeError: try: .... except IndexError: ....
and if I can't specify the specific exception, this is not helpful. On the other hand
try: .... except KeyError try: .... except AttributeError try: .... except IndexError: ....
only really saves me two colons and some whitespace. If the language had this feature, I'd use it, but that doesn't make it worth adding.
--- Bruce

On 12/28/2013 09:05 PM, Andrew Barnert wrote:
On Dec 28, 2013, at 8:10, Chris Angelico <rosuav@gmail.com> wrote:
There is one thing, though, that I'm seeing of all this. Exception throwing is asymmetrical: you can attempt a series of statements until one fails, but there's no convenient syntax to attempt a series of statements until one succeeds. I wonder, could the more general case be solved? Is there a way to, without stupid stuff like eval, wrap up a few statements so they can be executed in a loop:
def import_any(statement_list): for try_me in statement_list: try: # uhh, this is the bit I'm not sure about... try_me() # this would work if they're functions instead! return except ImportError: pass raise ImportError
This works for a set of functions, but not for a bunch of "from this import that" statements. Would it be worth mangling the top of your script until it can be done with importlib or __import__? Doesn't seem nearly as clean, somehow.
This is a clever idea.
If you could work out a clean syntax for the "try until one works" syntax, it would solve a wider range of problems than just this import issue.
It strikes me that there's some similarity with if/elif/else. Maybe just:
try: stuff except try: other stuff except try: different stuff except Exception as e: deal with it
But there are a lot of open questions. First, "except try" looks horrible, but I can't think of anything better.
I would buy (if cheap!): try: stuff else try: other stuff else try: different stuff except Exception as e: deal with it
If they all fail, do you only get the last exception, or are they all chained together?
Same issue in parsing in front of a choice (ordered or not): when match fails, what helpful error message? The parser cannot know which branch should have matched, so the only solution is to list failure causes of every branch; but branches may hold choices themselves, etc... expected: p = a | b| c at position: .... found: ... expected: a = ... at position: .... found: ... expected: b = x | y at position: .... found: ... expected: x = ... at position: .... found: ... expected: y = ... at position: .... found: ... expected: c = ... at position: .... found: ... This suggests that a general pattern for such an (ordered) choice of potential actions should not be modeled after exception catching; except (sic) for the failure branch in case none of them runs. My solution in parsing is only giving a general error (the first block above), but providing a solution (a test check tool func, the building block of test suites) for the user to try each potential branch individually (easily, quickly, and with helpful feedback). pat.check(str)
Would there be a use for a sequence like this without except on the end (so if they all fail, it just raises)? Can you put an exception type or tuple between the "except try"? What about an as clause (so the block could use it)?
I would require the general failure branch in syntax, for safety, like ordinary; with the same contents contents beeing the same: "pass" or "assert False". [1] Denis [1] I take the opportunity to ask: is there a builtin exception or other means to say "this block should never be reached"?

On Dec 29, 2013, at 1:41, spir <denis.spir@gmail.com> wrote:
"except try" looks horrible, but I can't think of anything better.
I would buy (if cheap!):
try: stuff else try: other stuff else try: different stuff except Exception as e: deal with it
The advantage of "except try" is that it leaves the door open for specifying only certain exceptions instead of all, which would be useful in some cases. But the advantage of "else try" is that it closes that door, eliminating most of the other questions I and others raised. It's clearly pure syntactic sugar with no ambiguity. Maybe that's a better idea.

On 30 Dec 2013 08:24, "Andrew Barnert" <abarnert@yahoo.com> wrote:
On Dec 29, 2013, at 1:41, spir <denis.spir@gmail.com> wrote:
"except try" looks horrible, but I can't think of anything better.
I would buy (if cheap!):
try: stuff else try: other stuff else try: different stuff except Exception as e: deal with it
The advantage of "except try" is that it leaves the door open for
specifying only certain exceptions instead of all, which would be useful in some cases.
But the advantage of "else try" is that it closes that door, eliminating
most of the other questions I and others raised. It's clearly pure syntactic sugar with no ambiguity. Maybe that's a better idea. The else block triggers when no exception was thrown, so even if this idea was to be accepted at all (which seems unlikely), that particular spelling definitely wouldn't be accepted for something that only triggers when an exception is thrown. In practice, the existing more general solution of extracting an appropriately named function is likely to improve readability more than adding a new variation on the already complex try/except/else/finally construct, which is why I consider it unlikely that a change along these lines would be accepted. Cheers, Nick.
_______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/

On 12/30/2013 01:24 AM, Nick Coghlan wrote:
On 30 Dec 2013 08:24, "Andrew Barnert" <abarnert@yahoo.com> wrote:
On Dec 29, 2013, at 1:41, spir <denis.spir@gmail.com> wrote:
"except try" looks horrible, but I can't think of anything better.
I would buy (if cheap!):
try: stuff else try: other stuff else try: different stuff except Exception as e: deal with it
The advantage of "except try" is that it leaves the door open for
specifying only certain exceptions instead of all, which would be useful in some cases.
But the advantage of "else try" is that it closes that door, eliminating
most of the other questions I and others raised. It's clearly pure syntactic sugar with no ambiguity. Maybe that's a better idea.
The else block triggers when no exception was thrown, so even if this idea was to be accepted at all (which seems unlikely), that particular spelling definitely wouldn't be accepted for something that only triggers when an exception is thrown.
I guess mean the else block in a 'normal' "try...except...else" construct? In this different form, there "else try", not just "else". I understood it as a single keyword (maybe read it elsetry, somewhat like elif) that denotes different semantics.
In practice, the existing more general solution of extracting an appropriately named function is likely to improve readability more than adding a new variation on the already complex try/except/else/finally construct, which is why I consider it unlikely that a change along these lines would be accepted.
After some more reflexion, I find this general pattern of "chained try" (new thread title) really meaningful and useful, but maybe too rare to deserve proper syntax. However, what is the proper way to express it using current Python features? Clearly, a series of nested try/except (compare: a series of nested if/else if python had no elif) is not the right tool, in my view, because try/except is to be used whenever the except branch is rare (semantically and practically, because itis clstly). What else? Try/elsetry would not need to trigger actual exceptions with full error objects, exception catching, and stack unwinding (the whole machinary), but only set a plain flag meaning "this branch fails to execute normally [1]. Denis [1] Could be a global bit or other var in the implementation, a CPU register, or even the carry flag in the CPU. See also: [https://www.lyngvig.org/%2FTeknik%2FA-Proposal-for-Exception-Handling-in-C]

On Mon, Dec 30, 2013 at 12:24 AM, spir <denis.spir@gmail.com> wrote:
After some more reflexion, I find this general pattern of "chained try" (new thread title) really meaningful and useful, but maybe too rare to deserve proper syntax. However, what is the proper way to express it using current Python features?
Clearly, a series of nested try/except (compare: a series of nested if/else if python had no elif) is not the right tool, in my view, because try/except is to be used whenever the except branch is rare (semantically and practically, because itis clstly). What else?
Try/elsetry would not need to trigger actual exceptions with full error objects, exception catching, and stack unwinding (the whole machinary), but only set a plain flag meaning "this branch fails to execute normally [1].
If you, instead of raising an exception, return None or that thing, then you can do things as so: return foo() or bar() or baz() This can't work if None is a reasonable value rather than just an error value (which is often why one switches to exceptions to begin with), but it works OK much of the time, and works OK all of the time in some other programming languages that are built around this idiom. -- Devin

On 12/28/2013 05:10 PM, Chris Angelico wrote:
On Sun, Dec 29, 2013 at 1:59 AM, spir <denis.spir@gmail.com> wrote:
This would also be allowed:
from this or that or another import spam
We'd also, or rather, need:
from this import foo or that import bar or another import baz as spam
which starts to be a bit complicated... Maybe (or perhaps) with parens:
from ((this import foo) or (that import bar) or (another import baz)) as spam
Can't say I like that variant - getting complicated and hard to read, even with parens. If you're importing different names from different modules, it's going to get very long, and then people are going to want to split it across lines, and then the obvious question is: what's been gained over the try/except variant?
There is one thing, though, that I'm seeing of all this. Exception throwing is asymmetrical: you can attempt a series of statements until one fails, but there's no convenient syntax to attempt a series of statements until one succeeds.
This is the logic of ordered choice (in parsing) I evoked in previous post, isn't it? Also same logic as 'find_first' funcs or the like (or of python's 'any' I guess).
I wonder, could the more general case be solved? Is there a way to, without stupid stuff like eval, wrap up a few statements so they can be executed in a loop:
def import_any(statement_list): for try_me in statement_list: try: # uhh, this is the bit I'm not sure about... try_me() # this would work if they're functions instead! return except ImportError: pass raise ImportError
This works for a set of functions, but not for a bunch of "from this import that" statements. Would it be worth mangling the top of your script until it can be done with importlib or __import__? Doesn't seem nearly as clean, somehow.
You seem to be asking for kinds of ruby blocks (or procs?), aren't you? Very practicle at times (while I'm not a fan of them, abuse leads to less readable code, as in FP). I'd enjoy them in python to encode conditional actions, like game events: a kind of pair (cause_state, effect_action) with a generic logic. In Python, one has to encode every cause and every action as separate functions, because they are distinct pieces of (named) data, while typically they're both one-liners (eg: if a unit steps on this very hex, add 15% to its health points). Denis

On Thu, Dec 26, 2013 at 5:57 PM, Amber Yust <amber.yust@gmail.com> 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.
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. 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.
_______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Such idioms are common. Though I don't think we should encourage their use. That said, if you want to have something like this added it should not use a new keyword ("maybe") but should use what we have. These look odd to me but are possible ideas: import foo else foo = None from foo import bar else bar = None that reuse of else on import statements would also enable the other idiom of importing one of several things to a single name: import foo as x else import bar as x Just tossing those out there. I'm not convinced this is worth adding to the language. -gps

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. 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. 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. _______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/

On Thu, Dec 26, 2013 at 5:57 PM, Amber Yust <amber.yust@gmail.com> wrote:
It's a fairly standard pattern to see things like this:
try: import foo except ImportError: foo = None
I would rarely, if ever, follow this pattern, although I *would* do conditional import fairly often. E.g. these are things I might do (well, not really these specific ones, but just as pattern examples): try: from math import pi except ImportError: pi = 3.1415 Or: try: import fancymodule as mod except ImportError: import simpler_version as mod Or: try: from mymod import needed_func except ImportError: def needed_func(a,b,c): "Bare bones implementation of more general function" return a*b + c Or even: try: import cool_feature FEATURE_AVAIL = True except ImportError: FEATURE_AVAIL = False What these have in common is that they are each specific to the context, and actually have nothing much in common other than the possibility import might fail. The special case of defining a missing module as 'None' is something I will probably never want to do... and therefore definitely have no desire for special syntax to do it. -- Keeping medicines from the bloodstreams of the sick; food from the bellies of the hungry; books from the hands of the uneducated; technology from the underdeveloped; and putting advocates of freedom in prisons. Intellectual property is to the 21st century what the slave trade was to the 16th. On Fri, Dec 27, 2013 at 8:30 AM, David Mertz <mertz@gnosis.cx> 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.
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. 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.
_______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
-- Keeping medicines from the bloodstreams of the sick; food from the bellies of the hungry; books from the hands of the uneducated; technology from the underdeveloped; and putting advocates of freedom in prisons. Intellectual property is to the 21st century what the slave trade was to the 16th.

I often do this: try: import json except ImportError: import simplejson as json Or: try: import optional_feature except ImportError: HAS_OPTIONAL_FEATURE = False else: HAS_OPTIONAL_FEATURE = True I think these two cases are fairly common. So why not have something like this?: import json or simplejson as json On 12/27/2013 06:00 PM, David Mertz wrote:
On Thu, Dec 26, 2013 at 5:57 PM, Amber Yust <amber.yust@gmail.com <mailto:amber.yust@gmail.com>> wrote:
It's a fairly standard pattern to see things like this:
try: import foo except ImportError: foo = None
I would rarely, if ever, follow this pattern, although I *would* do conditional import fairly often. E.g. these are things I might do (well, not really these specific ones, but just as pattern examples):
try: from math import pi except ImportError: pi = 3.1415
Or:
try: import fancymodule as mod except ImportError: import simpler_version as mod
Or:
try: from mymod import needed_func except ImportError: def needed_func(a,b,c): "Bare bones implementation of more general function" return a*b + c
Or even:
try: import cool_feature FEATURE_AVAIL = True except ImportError: FEATURE_AVAIL = False
What these have in common is that they are each specific to the context, and actually have nothing much in common other than the possibility import might fail. The special case of defining a missing module as 'None' is something I will probably never want to do... and therefore definitely have no desire for special syntax to do it.
-- Keeping medicines from the bloodstreams of the sick; food from the bellies of the hungry; books from the hands of the uneducated; technology from the underdeveloped; and putting advocates of freedom in prisons. Intellectual property is to the 21st century what the slave trade was to the 16th.
On Fri, Dec 27, 2013 at 8:30 AM, David Mertz <mertz@gnosis.cx <mailto:mertz@gnosis.cx>> 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.
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. 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.

On 27Dec2013 01:57, Amber Yust <amber.yust@gmail.com> 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.
It seems like it'd be useful and clean to have a syntax that looked like this:
maybe import foo [...snip...]
The problem here is that the only reason to import as above is to have access to the name "foo". What is you contingency plan for the failed import? How does the code cope without "foo". I'd rather have an ImportError at start than an arbitrarily delayed and harder to diagnose NameError much later. Because of this, I'd argue you should almost always want the except: clause if this is realistic, because you need to have a plan for the case of failure. I agree the try/except is wordy and possibly ugly, but I think it is usually needed when a failed import is not to be fatal. Cheers, -- Cameron Simpson <cs@zip.com.au> Every particle continues in its state of rest or uniform motion in a straight line except insofar as it doesn't. - Sir Arther Eddington
participants (13)
-
Amber Yust
-
Andrew Barnert
-
Bruce Leban
-
Cameron Simpson
-
Chris Angelico
-
David Mertz
-
Devin Jeanpierre
-
Gregory P. Smith
-
Mathias Panzenböck
-
Nick Coghlan
-
Ryan Gonzalez
-
spir
-
Steven D'Aprano