避免“if x:return x”语句的Pythonic方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/36117583/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Pythonic way to avoid "if x: return x" statements
提问by Bernard
I have a method that calls 4 other methods in sequence to check for specific conditions, and returns immediately (not checking the following ones) whenever one returns something Truthy.
我有一个方法,它依次调用 4 个其他方法来检查特定条件,并在返回真实值时立即返回(不检查以下方法)。
def check_all_conditions():
x = check_size()
if x:
return x
x = check_color()
if x:
return x
x = check_tone()
if x:
return x
x = check_flavor()
if x:
return x
return None
This seems like a lot of baggage code. Instead of each 2-line if statement, I'd rather do something like:
这似乎是很多行李代码。而不是每个 2 行 if 语句,我宁愿做这样的事情:
x and return x
But that is invalid Python. Am I missing a simple, elegant solution here? Incidentally, in this situation, those four check methods may be expensive, so I do not want to call them multiple times.
但那是无效的 Python。我在这里错过了一个简单、优雅的解决方案吗?顺便说一句,在这种情况下,这四个检查方法可能很昂贵,所以我不想多次调用它们。
回答by timgeb
Alternatively to Martijn's fine answer, you could chain or
. This will return the first truthy value, or None
if there's no truthy value:
除了 Martijn 的好答案,您还可以链接or
. 这将返回第一个真值,或者None
如果没有真值:
def check_all_conditions():
return check_size() or check_color() or check_tone() or check_flavor() or None
Demo:
演示:
>>> x = [] or 0 or {} or -1 or None
>>> x
-1
>>> x = [] or 0 or {} or '' or None
>>> x is None
True
回答by Martijn Pieters
You could use a loop:
您可以使用循环:
conditions = (check_size, check_color, check_tone, check_flavor)
for condition in conditions:
result = condition()
if result:
return result
This has the added advantage that you can now make the number of conditions variable.
这具有额外的优势,您现在可以使条件数量可变。
You could use map()
+ filter()
(the Python 3 versions, use the future_builtins
versionsin Python 2) to get the first such matching value:
您可以使用map()
+ filter()
(Python 3 版本,使用Python 2 中的future_builtins
版本)来获取第一个这样的匹配值:
try:
# Python 2
from future_builtins import map, filter
except ImportError:
# Python 3
pass
conditions = (check_size, check_color, check_tone, check_flavor)
return next(filter(None, map(lambda f: f(), conditions)), None)
but if this is more readable is debatable.
但如果这更具可读性是有争议的。
Another option is to use a generator expression:
另一种选择是使用生成器表达式:
conditions = (check_size, check_color, check_tone, check_flavor)
checks = (condition() for condition in conditions)
return next((check for check in checks if check), None)
回答by Hyman Aidley
Don't change it
不要改变它
There are other ways of doing this as the various other answers show. None are as clear as your original code.
正如其他各种答案所示,还有其他方法可以做到这一点。没有一个像您的原始代码那样清晰。
回答by Wayne Werner
In effectively the same answer as timgeb, but you could use parenthesis for nicer formatting:
实际上与 timgeb 的答案相同,但您可以使用括号进行更好的格式设置:
def check_all_the_things():
return (
one()
or two()
or five()
or three()
or None
)
回答by Phil Frost
According to Curly's law, you can make this code more readable by splitting two concerns:
根据Curly 定律,您可以通过拆分两个关注点来使此代码更具可读性:
- What things do I check?
- Has one thing returned true?
- 我要检查哪些项目?
- 一件事回归真了吗?
into two functions:
分为两个功能:
def all_conditions():
yield check_size()
yield check_color()
yield check_tone()
yield check_flavor()
def check_all_conditions():
for condition in all_conditions():
if condition:
return condition
return None
This avoids:
这避免了:
- complicated logical structures
- really long lines
- repetition
- 复杂的逻辑结构
- 很长的队伍
- 重复
...while preserving a linear, easy to read flow.
...同时保持线性、易于阅读的流程。
You can probably also come up with even better function names, according to your particular circumstance, which make it even more readable.
根据您的特定情况,您可能还可以想出更好的函数名称,这使其更具可读性。
回答by Phil Frost
This is a variant of Martijns first example. It also uses the "collection of callables"-style in order to allow short-circuiting.
这是 Martijns 第一个示例的变体。它还使用“可调用集合”样式以允许短路。
Instead of a loop you can use the builtin any
.
您可以使用内置的any
.
conditions = (check_size, check_color, check_tone, check_flavor)
return any(condition() for condition in conditions)
Note that any
returns a boolean, so if you need the exact return value of the check, this solution will not work. any
will not distinguish between 14
, 'red'
, 'sharp'
, 'spicy'
as return values, they will all be returned as True
.
请注意,any
返回一个布尔值,因此如果您需要检查的确切返回值,则此解决方案将不起作用。any
不会区分14
, 'red'
, 'sharp'
,'spicy'
作为返回值,它们都将作为 返回True
。
回答by zwol
Have you considered just writing if x: return x
all on one line?
您是否考虑过将if x: return x
所有内容写在一行上?
def check_all_conditions():
x = check_size()
if x: return x
x = check_color()
if x: return x
x = check_tone()
if x: return x
x = check_flavor()
if x: return x
return None
This isn't any less repetitivethan what you had, but IMNSHO it reads quite a bit smoother.
这并不比你所拥有的重复性更少,但 IMNSHO 它读起来相当流畅。
回答by ngasull
I'm quite surprised nobody mentioned the built-in any
which is made for this purpose:
我很惊讶没有人提到any
为此目的而制作的内置函数:
def check_all_conditions():
return any([
check_size(),
check_color(),
check_tone(),
check_flavor()
])
Note that although this implementation is probably the clearest, it evaluates all the checks even if the first one is True
.
请注意,尽管此实现可能是最清晰的,但它会评估所有检查,即使第一个是True
.
If you really need to stop at the first failed check, consider using reduce
which is made to convert a list to a simple value:
如果您确实需要在第一次失败的检查时停止,请考虑使用reduce
which is made 将列表转换为简单值:
def check_all_conditions():
checks = [check_size, check_color, check_tone, check_flavor]
return reduce(lambda a, f: a or f(), checks, False)
reduce(function, iterable[, initializer])
: Apply function of two arguments cumulatively to the items of iterable, from left to right, so as to reduce the iterable to a single value. The left argument, x, is the accumulated value and the right argument, y, is the update value from the iterable. If the optional initializer is present, it is placed before the items of the iterable in the calculation
reduce(function, iterable[, initializer])
: 将两个参数的函数从左到右累加应用于iterable的项,从而将iterable减少为单个值。左参数 x 是累加值,右参数 y 是可迭代对象的更新值。如果存在可选的初始化器,它会被放置在计算中的可迭代项之前
In your case:
在你的情况下:
lambda a, f: a or f()
is the function that checks that either the accumulatora
or the current checkf()
isTrue
. Note that ifa
isTrue
,f()
won't be evaluated.checks
contains check functions (thef
item from the lambda)False
is the initial value, otherwise no check would happen and the result would always beTrue
lambda a, f: a or f()
是检查累加器a
或当前检查f()
是否为 的函数True
。请注意,如果a
是True
,f()
则不会被评估。checks
包含检查函数(f
来自 lambda的项目)False
是初始值,否则不会发生检查,结果总是True
any
and reduce
are basic tools for functional programming. I strongly encourage you to train these out as well as map
which is awesome too!
any
而reduce
对于函数式编程的基本工具。我强烈鼓励你训练这些,map
这也很棒!
回答by Phinet
If you want the same code structure, you could use ternary statements!
如果你想要相同的代码结构,你可以使用三元语句!
def check_all_conditions():
x = check_size()
x = x if x else check_color()
x = x if x else check_tone()
x = x if x else check_flavor()
return x if x else None
I think this looks nice and clear if you look at it.
如果你看它,我认为这看起来很好很清楚。
Demo:
演示:
回答by juandesant
For me, the best answer is that from @phil-frost, followed by @wayne-werner's.
对我来说,最好的答案来自@phil-frost,其次是@wayne-werner。
What I find interesting is that no one has said anything about the fact that a function will be returning many different data types, which will make then mandatory to do checks on the type of x itself to do any further work.
我觉得有趣的是,没有人说过函数将返回许多不同的数据类型这一事实,这将强制检查 x 本身的类型以做任何进一步的工作。
So I would mix @PhilFrost's response with the idea of keeping a single type:
所以我会将@PhilFrost 的回应与保持单一类型的想法混合在一起:
def all_conditions(x):
yield check_size(x)
yield check_color(x)
yield check_tone(x)
yield check_flavor(x)
def assessed_x(x,func=all_conditions):
for condition in func(x):
if condition:
return x
return None
Notice that x
is passed as an argument, but also all_conditions
is used as a passed generator of checking functions where all of them get an x
to be checked, and return True
or False
. By using func
with all_conditions
as default value, you can use assessed_x(x)
, or you can pass a further personalised generator via func
.
请注意,x
它作为参数传递,但也all_conditions
用作检查函数的传递生成器,其中所有检查函数都得到 anx
被检查,并返回True
or False
。通过使用func
withall_conditions
作为默认值,您可以使用assessed_x(x)
,或者您可以通过 传递进一步的个性化生成器func
。
That way, you get x
as soon as one check passes, but it will always be the same type.
这样一来,只要x
通过了一次检查,您就会得到,但它始终是相同的类型。