条件中可以有赋值吗?
在条件语句中可以进行赋值吗?
比如说:
if (a=some_func()):
# Use a
10 个回答
不,这个功能并没有得到BDFL的认可。
从我的角度来看,Guido van Rossum,也就是“终身仁慈独裁者”,一直在努力保持Python的简单性。我们可以对他做出的一些决定提出不同意见——我希望他能更频繁地说‘不’。但我认为,Python并不是由一个委员会来设计的,而是由一个基于能力的“顾问委员会”来进行筛选,主要依靠一个设计者的感觉,这样的方式创造出了一个非常不错的编程语言。
更新 - 原始回答在底部
Python 3.8 将引入 PEP572
摘要
这是一个提案,目的是创建一种在表达式中给变量赋值的方法,使用的语法是NAME := expr
。新增了一个异常TargetScopeError
,并且评估顺序有一个变化。
https://lwn.net/Articles/757713/
“PEP 572 的混乱”是2018年Python语言峰会的一个话题,由终身仁慈独裁者(BDFL)Guido van Rossum 主持。PEP 572 试图将赋值表达式(或称“内联赋值”)添加到语言中,但在python-dev邮件列表上经历了长时间的讨论,甚至在python-ideas上也进行了多轮讨论。这些讨论常常充满争议,信息量巨大,以至于很多人可能都选择了忽略。在峰会上,Van Rossum 概述了这个特性提案,他似乎倾向于接受,但他也想讨论如何避免未来出现这种讨论爆炸的情况。
https://www.python.org/dev/peps/pep-0572/#examples-from-the-python-standard-library
来自Python标准库的示例
site.py env_base 只在这些行中使用,将其赋值放在if语句中可以将其作为块的“头部”。
当前:
env_base = os.environ.get("PYTHONUSERBASE", None) if env_base: return env_base
改进:
if env_base := os.environ.get("PYTHONUSERBASE", None): return env_base _pydecimal.py
避免嵌套的if语句,并减少一个缩进级别。
当前:
if self._is_special: ans = self._check_nans(context=context) if ans: return ans
改进:
if self._is_special and (ans := self._check_nans(context=context)): return ans
copy.py 代码看起来更整齐,避免了多个嵌套的if语句。(关于这个例子的来源,请参见附录A。)
当前:
reductor = dispatch_table.get(cls) if reductor: rv = reductor(x) else: reductor = getattr(x, "__reduce_ex__", None) if reductor: rv = reductor(4) else: reductor = getattr(x, "__reduce__", None) if reductor: rv = reductor() else: raise Error( "un(deep)copyable object of type %s" % cls)
改进:
if reductor := dispatch_table.get(cls): rv = reductor(x) elif reductor := getattr(x, "__reduce_ex__", None): rv = reductor(4) elif reductor := getattr(x, "__reduce__", None): rv = reductor() else: raise Error("un(deep)copyable object of type %s" % cls) datetime.py
tz 只用于 s += tz,将其赋值放在if语句内部有助于显示其作用范围。
当前:
s = _format_time(self._hour, self._minute, self._second, self._microsecond, timespec) tz = self._tzstr() if tz: s += tz return s
改进:
s = _format_time(self._hour, self._minute, self._second, self._microsecond, timespec) if tz := self._tzstr(): s += tz return s
sysconfig.py 在while条件中调用 fp.readline(),在if语句中调用 .match() 使代码更紧凑,而不
使其更难理解。
当前:
while True: line = fp.readline() if not line: break m = define_rx.match(line) if m: n, v = m.group(1, 2) try: v = int(v) except ValueError: pass vars[n] = v else: m = undef_rx.match(line) if m: vars[m.group(1)] = 0
改进:
while line := fp.readline(): if m := define_rx.match(line): n, v = m.group(1, 2) try: v = int(v) except ValueError: pass vars[n] = v elif m := undef_rx.match(line): vars[m.group(1)] = 0
简化列表推导式 通过捕获条件,列表推导式可以高效地映射和过滤:
results = [(x, y, x/y) for x in input_data if (y := f(x)) > 0]
同样,子表达式可以在主表达式中重复使用,通过第一次使用时给它命名:
stuff = [[y := f(x), x/y] for x in range(5)]
注意,在这两种情况下,变量 y 都绑定在包含的作用域中(即与 results 或 stuff 在同一层级)。
捕获条件值 赋值表达式可以在if或while语句的头部有效使用:
# Loop-and-a-half while (command := input("> ")) != "quit": print("You entered:", command) # Capturing regular expression match objects # See, for instance, Lib/pydoc.py, which uses a multiline spelling # of this effect if match := re.search(pat, text): print("Found:", match.group(0)) # The same syntax chains nicely into 'elif' statements, unlike the # equivalent using assignment statements. elif match := re.search(otherpat, text): print("Alternate found:", match.group(0)) elif match := re.search(third, text): print("Fallback found:", match.group(0)) # Reading socket data until an empty string is returned while data := sock.recv(8192): print("Received data:", data)
特别是在while循环中,这可以消除无限循环、赋值和条件的需要。它还在一个循环中创建了一个平滑的平行关系,该循环简单地使用函数调用作为条件,而另一个则使用该条件并使用实际值。
Fork 来自低级UNIX世界的一个例子:
if pid := os.fork(): # Parent code else: # Child code
原始回答
http://docs.python.org/tutorial/datastructures.html
请注意,在Python中,与C不同,赋值不能出现在表达式中。C程序员可能会对此抱怨,但这避免了C程序中常见的一类问题:在表达式中输入=时,实际上是想输入==。
另见:
http://effbot.org/pyfaq/why-can-t-i-use-an-assignment-in-an-expression.htm
为什么不试试看呢?
>>> def some_func():
... return 2
...
>>> if (a = some_func()):
File "<stdin>", line 1
if (a = some_func()):
^
SyntaxError: invalid syntax
所以,不行。
更新: 在Python 3.8中,这种写法是可能的(语法不同)
if a := some_func():