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

时间:2010-04-08 22:45:50

标签: python

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

对于前。

if (a=some_func()):
    # Use a

10 个答案:

答案 0 :(得分:89)

为什么不尝试一下?

>>> def some_func():
...   return 2
... 
>>> a = 2
>>> if (a = some_func()):
  File "<stdin>", line 1
    if (a = some_func()):
          ^
SyntaxError: invalid syntax
>>> 

所以,没有。

答案 1 :(得分:36)

不,BDFL不喜欢这个功能。

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

答案 2 :(得分:25)

更新 - 原始答案靠近底部

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都在包含中绑定   范围(即与结果或东西处于同一水平)。

     

捕获条件值可以在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

答案 3 :(得分:16)

不是直接的,按this old recipe of mine - 但正如食谱所说,构建语义等价物很容易,例如:如果你需要直接从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形式,如果您确切知道假值({1}}在返回假值(例如somefunc)时可能返回的内容,则是

0

因此,在这种特定情况下,重构将非常简单; - )。

如果返回可能任何类型的假值(0,for a in iter(somefunc, 0): # use a None,...),则有一种可能性:

''

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

import itertools

for a in itertools.takewhile(lambda x: x, iter(somefunc, object())):
    # use a

答案 4 :(得分:13)

是的,但仅适用于Python 3.8及更高版本。

PEP 572提出了分配表达式,并且已经被接受。

引用PEP的Syntax and semantics部分:

# 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

答案 5 :(得分:4)

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

答案 6 :(得分:3)

由于Python 3.8 new feature,可以在此版本中执行此操作,尽管不使用=,而是使用类似Ada的赋值运算符:=。来自文档的示例:

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

答案 7 :(得分:2)

您可以定义一个功能来为您分配:

def assign(name, value):
    import inspect
    frame = inspect.currentframe()
    try:
        locals_ = frame.f_back.f_locals
    finally:
        del frame 
    locals_[name] = value
    return value

if assign('test', 0):
    print("first", test)
elif assign('xyz', 123):
    print("second", xyz)

答案 8 :(得分:1)

分配在条件非法的原因之一是犯错误更容易分配真或假:

some_variable = 5

# This does not work
# if True = some_variable:
#   do_something()

# This only works in Python 2.x
True = some_variable

print True  # returns 5

在Python 3中,True和False是关键字,因此不再存在风险。

答案 9 :(得分:1)

赋值运算符-也非正式地称为海象运算符-于2018年2月28日在PEP572中创建。

为了完整起见,我将发布相关部分,以便您可以比较3.7和3.8之间的差异:

3.7
---
if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT
test: or_test ['if' or_test 'else' test] | lambdef
test_nocond: or_test | lambdef_nocond
lambdef: 'lambda' [varargslist] ':' test
lambdef_nocond: 'lambda' [varargslist] ':' test_nocond
or_test: and_test ('or' and_test)*
and_test: not_test ('and' not_test)*
not_test: 'not' not_test | comparison
comparison: expr (comp_op expr)*

3.8
---
if_stmt: 'if' namedexpr_test ':' suite ('elif' namedexpr_test ':' suite)* ['else' ':' suite]
namedexpr_test: test [':=' test]                         <---- WALRUS OPERATOR!!!
test: or_test ['if' or_test 'else' test] | lambdef
or_test: and_test ('or' and_test)*
and_test: not_test ('and' not_test)*
not_test: 'not' not_test | comparison
comparison: expr (comp_op expr)*