[Python-Dev] PEP 463: Exception-catching expressions
Chris Angelico
rosuav at gmail.com
Sat Feb 22 12:13:58 CET 2014
On Sat, Feb 22, 2014 at 9:17 PM, Antoine Pitrou <solipsis at pitrou.net> wrote:
> On Sat, 22 Feb 2014 21:09:07 +1100
> Chris Angelico <rosuav at gmail.com> wrote:
>> On Sat, Feb 22, 2014 at 8:58 PM, Antoine Pitrou <solipsis at pitrou.net> wrote:
>> > On Sat, 22 Feb 2014 20:29:27 +1100
>> > Chris Angelico <rosuav at gmail.com> wrote:
>> >>
>> >> Which means that, fundamentally, EAFP is the way to do it. So if PEP
>> >> 463 expressions had existed from the beginning, hasattr() probably
>> >> wouldn't have been written - people would just use an
>> >> except-expression instead.
>> >
>> > Really? hasattr() is much easier to write than the corresponding
>> > except-expression.
>>
>> But would it be sufficiently easier to justify the creation of a
>> built-in?
>
> Well, can you propose the corresponding except-expression?
It's hard to do hasattr itself without something messy - the best I
can come up with is this:
hasattr(x,"y") <-> (x.y or True except AttributeError: False)
but the bulk of uses of it are immediately before attempting to use
the attribute. Many require multiple statements, so they'd be better
done as a full try/except:
cpython/python-gdb.py:1392:
if not hasattr(self._gdbframe, 'select'):
print ('Unable to select frame: '
'this build of gdb does not expose a
gdb.Frame.select method')
return False
self._gdbframe.select()
return True
becomes
try:
self._gdbframe.select()
return True
except AttributeError:
print ('Unable to select frame: '
'this build of gdb does not expose a
gdb.Frame.select method')
return False
but others are clearly expressions in disguise:
Lib/aifc.py:882:
if hasattr(f, 'mode'):
mode = f.mode
else:
mode = 'rb'
becomes
mode = (f.mode except AttributeError: 'rb')
(In fact, I'm adding that one to the PEP's examples section.)
Lib/cgi.py:145:
if hasattr(fp,'encoding'):
encoding = fp.encoding
else:
encoding = 'latin-1'
becomes
encoding = (fp.encoding except AttributeError: 'latin-1')
Some could be done either way. If hasattr didn't exist, then this:
Lib/argparse.py:597:
if hasattr(params[name], '__name__'):
params[name] = params[name].__name__
could be written instead as:
params[name] = (params[name].__name__
except AttributeError: params[name])
which is similar length and doesn't require a built-in.
Some are fairly clearly asking to be done as try/except, irrespective
of this PEP:
Lib/decimal.py:449:
if hasattr(threading.current_thread(), '__decimal_context__'):
del threading.current_thread().__decimal_context__
becomes
try: del threading.current_thread().__decimal_context__
except AttributeError: pass
(also ibid:476)
Some are a bit of a mixture.
Lib/dis.py:40:
if hasattr(x, '__func__'): # Method
x = x.__func__
if hasattr(x, '__code__'): # Function
x = x.__code__
if hasattr(x, '__dict__'): # Class or module
... lots more code ...
Could be done as try/except; first part could be done cleanly as an expression.
This one's not quite as clean, but if hasattr didn't exist, this could
be done either of two ways:
Lib/fileinput.py:342:
if hasattr(os, 'O_BINARY'):
mode |= os.O_BINARY
As an expression:
mode |= (os.O_BINARY except AttributeError: 0)
Or as a statement:
try: mode |= os.O_BINARY
except AttributeError: pass
This one definitely would want to be changed, and is also going in the PEP:
Lib/inspect.py:1350:
return sys._getframe(1) if hasattr(sys, "_getframe") else None
becomes
return (sys._getframe(1) except AttributeError: None)
Lib/ntpath.py:558:
# Win9x family and earlier have no Unicode filename support.
supports_unicode_filenames = (hasattr(sys, "getwindowsversion") and
sys.getwindowsversion()[3] >= 2)
becomes
supports_unicode_filenames = (sys.getwindowsversion()[3] >= 2
except AttributeError: False)
Another ternary-if LBYL that could become an expression-except EAFP:
Lib/pdb.py:745:
globs = self.curframe.f_globals if hasattr(self, 'curframe') else None
becomes
globs = (self.curframe.f_globals except AttributeError: None)
although that will return None if self.curframe has no f_globals.
Another nice easy one:
Lib/pickletools.py:2227:
if hasattr(data, "tell"):
getpos = data.tell
else:
getpos = lambda: None
becomes
getpos = (data.tell except AttributeError: lambda: None)
I could continue this theme, but behold, as Rose Maybud said, I have
said enough.
There are definitely cases where a local hasattr function could be
useful, but if the code were already written to use try/except or an
except-expression, there aren't many that would justify the creation
of a builtin.
ChrisA
More information about the Python-Dev
mailing list