I thought about how to write a function that returns a value other than None that first appeared in short-circuit evaluation in Python.
First, as an example, execute the function get_answer ()
that evaluates three expressions, yahoo ()
, google ()
, and ʻask ()` in order, and returns a value other than None that appears first. I wrote get_answer.py normally. The operation has been confirmed with Python 2.7.3 and Python 3.2.3.
get_answer.py
#!/usr/bin/env python
# vim:fileencoding=utf-8
from __future__ import print_function
yahoo = lambda *_: print("in yahoo()") or None
google = lambda *_: print("in google()") or 0
ask = lambda *_: print("in ask()") or "draw"
def get_answer(question):
answer = yahoo(question)
if answer is None:
answer = google(question)
if answer is None:
answer = ask("sagami", question)
return answer
if __name__ == '__main__': # pragma: nocover
print("Answer is {}.".format(get_answer("1 - 1")))
When you do this,
in yahoo()
in google()
Answer is 0.
Is displayed. Evaluating google (question)
gave a non-None value of 0, so ʻask ("sagami ", question)` was not evaluated.
If you want to make the nesting of if statements shallow, the number of lines will increase slightly,
def get_answer(question):
answer = yahoo(question)
if answer is not None:
return answer
answer = google(question)
if answer is not None:
return answer
return ask("sagami", question)
You can also write like this. But this function
def get_answer(question):
return (yahoo(question) or
google(question) or
ask("sagami", question))
Or
def get_answer(question):
for answer in (yahoo(question),
google(question),
ask("sagami", question)):
if answer is not None:
return answer
return None
Cannot be written like. When the former is executed,
in yahoo()
in google()
in ask()
Answer is draw.
And 0, which is a value other than None, will be ignored, and when the latter is executed,
in yahoo()
in google()
in ask()
Answer is 0.
Therefore, even ʻask ("sagami", question) `, which does not need to be evaluated, will be evaluated.
As a result of various worries there, by using the decorator @anyone
,
@anyone
def get_answer(question):
yield yahoo(question)
yield google(question)
yield ask("sagami", question)
I came up with a way to write. The contents of @anyone
are
def anyone(function):
def _(*args, **kwargs):
for value in function(*args, **kwargs):
if value is not None:
return value
return None
return _
is. I think that get_answer ()
can be written simply, but how about it?
I would appreciate it if you could tell me if there is any other better way.
Below is get_answer.py rewritten using @ anyone
.
get_answer.py
#!/usr/bin/env python
# vim:fileencoding=utf-8
from __future__ import print_function
yahoo = lambda *_: print("in yahoo()") or None
google = lambda *_: print("in google()") or 0
ask = lambda *_: print("in ask()") or "draw"
def anyone(function):
def _(*args, **kwargs):
for value in function(*args, **kwargs):
if value is not None:
return value
return None
return _
@anyone
def get_answer(question):
yield yahoo(question)
yield google(question)
yield ask("sagami", question)
if __name__ == '__main__': # pragma: nocover
print("Answer is {}.".format(get_answer("1 - 1")))
Recommended Posts