一个If语句中有两个Walrus运算符



在1if语句中有两个walrus运算符的正确方法吗?

if (three:= i%3==0) and (five:= i%5 ==0):
arr.append("FizzBuzz")
elif three:
arr.append("Fizz")
elif five:
arr.append("Buzz")
else:
arr.append(str(i-1))

这个例子适用于CCD_ 1,但CCD_;未定义";。

逻辑运算符and仅有条件地计算其第二个操作数。没有正确的方法可以无条件地需要条件赋值。

相反,使用";二进制";运算符&,其无条件地评估其第二个操作数。

arr = []
for i in range(1, 25):
#                        v force evaluation of both operands
if (three := i % 3 == 0) & (five := i % 5 == 0):
arr.append("FizzBuzz")
elif three:
arr.append("Fizz")
elif five:
arr.append("Buzz")
else:
arr.append(str(i))
print(arr)
# ['1', '2', 'Fizz', '4', 'Buzz', 'Fizz', '7', '8', 'Fizz', 'Buzz', '11', ...]

相应地,可以使用|作为or的无条件变体。此外;xor";算子CCD_ 7根本不具有条件求值的等价项。

值得注意的是,二进制运算符将布尔值评估为纯布尔值——例如,False | TrueTrue而不是three0——但对于其他类型可能会有不同的工作方式。要使用二进制运算符在布尔上下文中评估任意值,如lists,请在赋值后将其转换为bool

#  |~~~ force list to boolean ~~| | force evaluation of both operands
#  v    v~ walrus-assign list ~vv v
if bool(lines := list(some_file)) & ((today := datetime.today()) == 0):
...

由于赋值表达式需要括号来表示正确的优先级,因此逻辑(andor(和二进制(&|^(运算符之间优先级不同的常见问题在这里无关紧要。

您遇到的问题是,由于短路,只有当three在此语句中为True时,才会分配five

if (three:= i%3==0) and (five:= i%5 ==0)

因此CCD_ 20通常不被分配,从而导致CCD_。

您可以通过形成一个包含walrus赋值的非空元组,然后在该元组之后使用five2和five来强制一个True值。

它并不比在if之前分配threefive更漂亮,但这很有效:

arr=[]
for i in range(1,26):
if (three:=i%3==0, five:=i%5==0) and three and five:
arr.append(f"{i} FizzBuzz")
elif three:
arr.append(f"{i} Fizz")
elif five:
arr.append(f"{i} Buzz")
else:
arr.append(f"{i}")
>>> arr
['1', '2', '3 Fizz', '4', '5 Buzz', '6 Fizz', '7', '8', '9 Fizz', '10 Buzz', '11', '12 Fizz', '13', '14', '15 FizzBuzz', '16', '17', '18 Fizz', '19', '20 Buzz', '21 Fizz', '22', '23', '24 Fizz', '25 Buzz']

任何非空元组在Python中都是True。形成它使(three:=i%3==0, five:=i%5==0)总是真实的,每次分配三个和五个。由于该元组为true,因此必须使用正确的值3和5来计算表达式的其余部分。

或者,使用if all((three:=i%3==0, five:=i%5==0)):,因为元组是在测试其内容之前形成的——即使所有短路;只有在元组形成之后才会发生这种情况。

这两种形式中的任何一种都可以轻松地重构为理解:

arr=[f"{i} FizzBuzz" if three and five 
else f"{i} Fizz" if three 
else f"{i} Buzz" if five 
else f"{i}" 
for i in range(1,26) if (three:=i%3==0, five:=i%5==0)]

或者,

arr=[f"{i} FizzBuzz" if all((three:=i%3==0, five:=i%5==0)) 
else f"{i} Fizz" if three 
else f"{i} Buzz" if five 
else f"{i}" for i in range(1,26)]

如果每个元素的结果不是布尔值,请注意构造if (three := i % 3 == 0) & (five := i % 5 == 0):。你可能会遇到一些意想不到的故障:

>>> bool((x:=3) & (y:=4))
False
>>> bool((x:=3) and (y:=4))
True   

唯一的解决方法是将bool应用于每个:

>>> bool(x:=3) & bool(y:=4)
True

BTW,说到元组,在Python中进行FizzBuzz类型挑战的较短方法:

fb={(True,True):"{} FizzBuzz", 
(True,False):"{} Fizz", 
(False,True):"{} Buzz", 
(False,False):"{}"}
arr=[fb[(i%3==0,i%5==0)].format(i) for i in range(1,26)]

如果你正在寻找新的,这种类型的问题对于Python 3.10+模式匹配来说是很自然的:

arr=[]
for i in range(1,26):
s=f"{i}"
match (i%3==0,i%5==0):
case (True, (True | False) as oth):
s+=" FizzBuzz" if oth else " Fizz"

case (False, True):
s+=" Buzz"

arr.append(s)   

相关内容

  • 没有找到相关文章

最新更新