Mailing List Archive

EAFP
Is the following LBYL:foo = 123if foo < 200:    do()If so, how to change to EAFP?Thanks!Sent from Samsung tablet.
--
https://mail.python.org/mailman/listinfo/python-list
Re: EAFP [ In reply to ]
On 14/05/2022 04.37, bryangan41 wrote:
> Is the following LBYL:foo = 123if foo < 200:    do()

Yes (once formatted for Python).


If so, how to change to EAFP?

Not sure if can. Let's alter the code to:

foo = 0

#and

def do():
return 5 / foo

Then, you will expect a ZeroDivisionError exception to be raised -
whereas with other values, there will (likely) be no problem.

Now, we have a clear identification for when 'forgiveness' will need to
be requested! The 'EAFP' solution encloses the function-call:

foo = 123
try:
do()
except ZeroDivisionError:
undo()


In the OP's code-snippet, the "200" criteria means there is no such
clean-cut and automatic 'failure' attached to, or implied by, foo's
value. However, we could define a custom-exception and 'raise the alarm'
when 'forgiveness' is required:

class ValueTooLargeError( ValueError):
"""Catch values larger than the valid range."""

def do():
if foo < 200:
...
else:
raise ValueTooLargeError

This is a pythonic-construct (and thus a recommendable coding-pattern),
in that the calling-routine can decide how to respond to the exception -
which many vary according to the specifics of do()'s re-use.


However, is it "EAFP"? We had to introduce the exact if-condition which
makes it "LBYL"!

Perhaps time for me to bow-out, and leave such to the philosophers...


Sent from Samsung tablet.

There are pills for that...
--
Regards,
=dn
--
https://mail.python.org/mailman/listinfo/python-list
Re: EAFP [ In reply to ]
On 13/05/2022 18:37, bryangan41 wrote:
> Is the following LBYL:foo = 123if foo < 200:    do()If so, how to change to EAFP?Thanks!Sent from Samsung tablet.

The distinction between look-before-you-leap and
easier-to-ask-forgiveness-than-permission is weaker than yo might expect.

When you write

filename = ...
if exists(filename):
with open(filename) as instream:
# do stuff
else:
# fallback

there are two checks for the file's existence, one explicit, and one
implicitly inside open() -- and worse, the first, explicit, check is
unreliable because between exists() and open() there is a small delay
that may be sufficient to create or delete the file. Therefore the
recommended (EAFP) version of the above is

filename = ...
try:
with open(filename) as instrem:
# do stuff
except FileNotFoundError
# fallback

or just

with open(filename) as instream:
# do stuff

if there is no meaningful fallback.

Regarding your example code, whether you can write an EAFP version for

if foo < 200:
do()

depends on the contents of do(). If do() fails in a well-defined way,
let's say by raising a FooAbove199 exception you can write just

do()

or, if you need a fallback

try:
do()
except FooAbove199:
# fallback

Note that if you change do() from

do():
# do stuff

to

def do():
if foo < 200:
# do stuff
else:
raise FooAbove199(f"Invalid {foo=!r}")

the

do()

invocation becomes EAFP even though you are actually performing the same
test as before.
--
https://mail.python.org/mailman/listinfo/python-list