是否可以在条件下进行分配?
对于前者
if (a=some_func()):
    # Use a
Jas*_*all 92
为什么不尝试一下呢?
>>> def some_func():
...   return 2
... 
>>> a = 2
>>> if (a = some_func()):
  File "<stdin>", line 1
    if (a = some_func()):
          ^
SyntaxError: invalid syntax
>>> 
所以不行.
Joh*_*ooy 41
Python 3.8将引入PEP572
摘要
这是一个使用符号NAME:= expr创建一种分配给表达式中变量的方法的提议.添加了一个新的异常,即TargetScopeError,评估顺序有一处更改.
https://lwn.net/Articles/757713/
"PEP 572混乱"是由仁慈的终身独裁者(BDFL)Guido van Rossum领导的2018年Python语言峰会的主题.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上将其作为块的"标题"移动.
当前:
Run Code Online (Sandbox Code Playgroud)env_base = os.environ.get("PYTHONUSERBASE", None) if env_base: return env_base改进:
Run Code Online (Sandbox Code Playgroud)if env_base := os.environ.get("PYTHONUSERBASE", None): return env_base _pydecimal.py避免嵌套if和删除一个缩进级别.
当前:
Run Code Online (Sandbox Code Playgroud)if self._is_special: ans = self._check_nans(context=context) if ans: return ans改进:
Run Code Online (Sandbox Code Playgroud)if self._is_special and (ans := self._check_nans(context=context)): return anscopy.py代码看起来更规则,避免多个嵌套if.(有关此示例的来源,请参阅附录A.)
当前:
Run Code Online (Sandbox Code Playgroud)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)改进:
Run Code Online (Sandbox Code Playgroud)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.pytz仅用于s + = tz,在if内部移动其赋值有助于显示其范围.
当前:
Run Code Online (Sandbox Code Playgroud)s = _format_time(self._hour, self._minute, self._second, self._microsecond, timespec) tz = self._tzstr() if tz: s += tz return s改进:
Run Code Online (Sandbox Code Playgroud)s = _format_time(self._hour, self._minute, self._second, self._microsecond, timespec) if tz := self._tzstr(): s += tz return ssysconfig.py在while条件下调用fp.readline()并在if行上调用.match()使代码更紧凑
让它更难理解.
当前:
Run Code Online (Sandbox Code Playgroud)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改进:
Run Code Online (Sandbox Code Playgroud)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简化列表推导通过捕获条件,列表推导可以有效地映射和过滤:
Run Code Online (Sandbox Code Playgroud)results = [(x, y, x/y) for x in input_data if (y := f(x)) > 0]类似地,子表达式可以在主表达式中重用,方法是在首次使用时为其指定名称:
Run Code Online (Sandbox Code Playgroud)stuff = [[y := f(x), x/y] for x in range(5)]请注意,在两种情况下,变量y都绑定在包含范围内(即与结果或填充相同的级别).
捕获条件值可以在if或while语句的标头中使用赋值表达式:
Run Code Online (Sandbox Code Playgroud)# 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世界的示例:
Run Code Online (Sandbox Code Playgroud)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-ti-use-an-assignment-in-an-expression.htm
Kev*_*tle 37
不,BDFL不喜欢这个功能.
从我所在的地方开始,Guido van Rossum,"仁慈的生活独裁者",努力让Python保持尽可能简单.我们可以对他做出的一些决定嗤之以鼻 - 我更喜欢他说'不"更常见的是.但事实上,没有一个委员会设计Python,而是一个信任的"顾问委员会",主要基于功绩,过滤一个设计师的敏感性,产生了一个很好的语言,恕我直言.
Ale*_*lli 16
不是直接的,根据我的这个旧配方 - 但是正如配方所说,构建语义等价物很容易,例如,如果你需要直接从C编码参考算法音译(当然,在重构为更惯用的Python之前; - ).即:
class DataHolder(object):
    def __init__(self, value=None): self.value = value
    def set(self, value): self.value = value; return value
    def get(self): return self.value
data = DataHolder()
while data.set(somefunc()):
  a = data.get()
  # use a
BTW,一个非常惯用的Pythonic形式,适用于你的特定情况,如果你确切地知道somefunc当它返回一个假值(例如0)时falsish值可能会返回,是
for a in iter(somefunc, 0):
  # use a
所以在这种特殊情况下,重构会非常简单;-).
如果返回可能是任何一种falsish值(0的None,''...),一种可能性是:
import itertools
for a in itertools.takewhile(lambda x: x, iter(somefunc, object())):
    # use a
但您可能更喜欢简单的自定义生成器:
def getwhile(func, *a, **k):
    while True:
      x = func(*a, **k)
      if not x: break
      yield x
for a in getwhile(somefunc):
    # use a
tim*_*geb 14
是的,但仅限于Python 3.8及以后版本.
PEP 572提出了作业表达,并已被接受.
引用PEP 的语法和语义部分:
# Handle a matched regex
if (match := pattern.search(data)) is not None:
    # Do something with match
# A loop that can't be trivially rewritten using 2-arg iter()
while chunk := file.read(8192):
   process(chunk)
# Reuse a value that's expensive to compute
[y := f(x), y**2, y**3]
# Share a subexpression between a comprehension filter clause and its output
filtered_data = [y for x in data if (y := f(x)) is not None]
在您的具体情况下,您将能够写作
if a := some_func():
    # Use a
感谢Python 3.8 的新功能,从这个版本开始就可以做这样的事情,尽管不使用=而是类似 Ada 的赋值运算符:=。文档中的示例:
# Handle a matched regex
if (match := pattern.search(data)) is not None:
    # Do something with match