我们可以在条件下进行任务吗?

Vis*_*hal 76 python

是否可以在条件下进行分配?

对于前者

if (a=some_func()):
    # Use a
Run Code Online (Sandbox Code Playgroud)

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
>>> 
Run Code Online (Sandbox Code Playgroud)

所以不行.

  • 这是故意禁止的,因为Guido,仁慈的蟒蛇独裁者,发现它们是不必要的,而且更加混乱而不是有用.这与没有后增量或预增量运算符(++)的原因相同. (31认同)
  • “为什么不尝试一下”-因为谁知道语法可能是什么?也许OP尝试过,但没有成功,但这并不意味着语法没有不同,或者没有一种方法可以做到这一点 (19认同)
  • 它来自[Python 3.8](https://www.python.org/dev/peps/pep-0572/) (17认同)
  • 有趣的事实:`:=`(赋值表达式)也称为[“海象运算符”](https://www.python.org/dev/peps/pep-0572/#toc-entry-1),因为如果将其视为基于文本的表情符号,它看起来像海象。:) (10认同)
  • 他确实允许在2.0中添加*增强分配*,因为`x = x + 1`需要额外的查找时间,而`x + = 1`稍快一点,但我确定他甚至不喜欢*那*许多.:-) (4认同)

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上将其作为块的"标题"移动.

当前:

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
Run Code Online (Sandbox Code Playgroud)

避免嵌套if和删除一个缩进级别.

当前:

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 ans
Run Code Online (Sandbox Code Playgroud)

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)
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.py
Run Code Online (Sandbox Code Playgroud)

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
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 s
Run Code Online (Sandbox Code Playgroud)

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
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)]
Run Code Online (Sandbox Code Playgroud)

请注意,在两种情况下,变量y都绑定在包含范围内(即与结果或填充相同的级别).

捕获条件值可以在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)
Run Code Online (Sandbox Code Playgroud)

特别是对于while循环,这可以消除无限循环,赋值和条件的需要.它还在一个循环之间创建一个平滑的并行,该循环简单地使用函数调用作为其条件,并且使用该函数调用作为其条件但也使用实际值.

Fork来自低级UNIX世界的示例:

if pid := os.fork():
    # Parent code
else:
    # Child code
Run Code Online (Sandbox Code Playgroud)

原始答案

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

  • @JonathanCross,这个“功能”实际上将在 3.8 中添加。它不太可能像它应该的那样谨慎使用 - 但至少它不是一个简单的 `=` (3认同)
  • @Hi-Angel 这实际上工作得很好(Python 3.10.8)。你只需要根据你实际想要表达的内容添加括号,即`a if (a := 1) == 1 else False`(产生`1`)或`a if (a := 1 == 1 ) else False`(产生“True”)。 (3认同)

Kev*_*tle 37

不,BDFL不喜欢这个功能.

从我所在的地方开始,Guido van Rossum,"仁慈的生活独裁者",努力让Python保持尽可能简单.我们可以对他做出的一些决定嗤之以鼻 - 我更喜欢他说'不"更常见的是.但事实上,没有一个委员会设计Python,而是一个信任的"顾问委员会",主要基于功绩,过滤一个设计师的敏感性,产生了一个很好的语言,恕我直言.

  • 简单?这个功能可以简化我的一些代码,因为它可以使它更紧凑,因此更具可读性.现在我需要两条线,而我曾经需要一条线.我从来没有说过为什么Python多年来拒绝其他编程语言的功能(并且通常是有很好的理由).特别是我们在这里讨论的这个功能非常非常有用. (14认同)
  • 较少的代码并不总是更简单或更易读.以递归函数为例.它的循环等效通常更具可读性. (5认同)

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
Run Code Online (Sandbox Code Playgroud)

BTW,一个非常惯用的Pythonic形式,适用于你的特定情况,如果你确切地知道somefunc当它返回一个假值(例如0)时falsish值可能会返回,是

for a in iter(somefunc, 0):
  # use a
Run Code Online (Sandbox Code Playgroud)

所以在这种特殊情况下,重构会非常简单;-).

如果返回可能是任何一种falsish值(0的None,''...),一种可能性是:

import itertools

for a in itertools.takewhile(lambda x: x, iter(somefunc, object())):
    # use a
Run Code Online (Sandbox Code Playgroud)

但您可能更喜欢简单的自定义生成器:

def getwhile(func, *a, **k):
    while True:
      x = func(*a, **k)
      if not x: break
      yield x

for a in getwhile(somefunc):
    # use a
Run Code Online (Sandbox Code Playgroud)


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]
Run Code Online (Sandbox Code Playgroud)

在您的具体情况下,您将能够写作

if a := some_func():
    # Use a
Run Code Online (Sandbox Code Playgroud)


Ign*_*ams 5

不。Python 中的赋值是一个语句,而不是一个表达式。


Jea*_*bre 5

感谢Python 3.8 的新功能,从这个版本开始就可以做这样的事情,尽管不使用=而是类似 Ada 的赋值运算符:=。文档中的示例:

# Handle a matched regex
if (match := pattern.search(data)) is not None:
    # Do something with match
Run Code Online (Sandbox Code Playgroud)