如何在Python列表推导式中执行多个表达式?(附循环转推导需求)
如何将带状态修改的for循环转为Python列表推导式
原需求代码
需要将以下for循环转换为列表推导式:
number = 10 deci_list = [] for i in sorted(list(range(9)), reverse=True): if 2**i <= number: deci_list.append(1) number -= 2**i else: deci_list.append(0)
尝试与错误
尝试的代码因在列表推导式的if-else表达式中加入赋值语句触发语法错误:
thing = sorted(list(range(9)), reverse=True) new_thing = ['1' if 2**i <= number number -= 2**i else '0' for i in thing]
报错信息:
new_thing = ['1' if 2**i <= number number -= 2**i else '0' for i in thing] ^^^^^^^^^^^^^^^^^^^^^ SyntaxError: expected 'else' after 'if' expression
问题原因
列表推导式中的if-else是表达式,不是可执行的语句块,不能在其中执行赋值操作(number -= 2**i属于赋值语句,会修改外部变量状态)。这种带副作用的操作不仅语法不允许,还会让代码可读性变差,容易引发意外问题。
解决方案
方案1:用生成器函数模拟原逻辑(最接近原循环,可读性高)
把原循环逻辑封装成生成器,再转成列表:
def generate_binary_bits(num): for i in sorted(range(9), reverse=True): power = 2 ** i if power <= num: yield 1 num -= power else: yield 0 number = 10 deci_list = list(generate_binary_bits(number))
方案2:位运算直接计算(更简洁,无副作用)
原代码本质是生成number的9位二进制表示(高位在前,不足补0),可以用位运算直接判断每一位:
number = 10 deci_list = [1 if (number & (1 << i)) else 0 for i in reversed(range(9))]
解释:1 << i等价于2**i,number & (1 << i)用来判断第i位是否为1;reversed(range(9))实现从8到0的遍历,和原循环的sorted(range(9), reverse=True)效果一致。
方案3:不推荐的列表推导式写法(带副作用)
如果非要用列表推导式,可以借助可变对象(比如列表)维护状态,但这种写法可读性极差,不建议使用:
number = [10] # 用列表包装,因为列表是可变对象 deci_list = [ 1 if (2**i <= number[0]) and (number.__setitem__(0, number[0]-2**i) or True) else 0 for i in sorted(range(9), reverse=True) ]
内容的提问来源于stack exchange,提问作者TheBoogeyMan
相关产品推荐
相关产品推荐

