是否可以在条件下进行分配?
对于前。
if (a=some_func()):
# Use a
答案 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)*