是否有条件分配作业?
对于前。
if (a=some_func()):
# Use a
Answers:
为什么不尝试一下呢?
>>> def some_func():
... return 2
...
>>> a = 2
>>> if (a = some_func()):
File "<stdin>", line 1
if (a = some_func()):
^
SyntaxError: invalid syntax
>>>
所以不行。
x = x + 1需要额外的查找时间,而x += 1有点快,但我敢肯定,他甚至不喜欢做那个了。:-)
Python 3.8将引入PEP572
摘要
这是创建一种使用NAME:= expr表示法分配表达式中变量的方法的建议。添加了一个新异常TargetScopeError,并且评估顺序有所更改。
https://lwn.net/Articles/757713/
“ PEP 572混乱”是由仁慈的生命独裁者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改进的:
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 anscopy.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.pytz仅用于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 ssysconfig.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循环,这可以消除对无限循环,赋值和条件的需求。它还在仅使用函数调用作为条件的循环与将其用作条件但也使用实际值的循环之间创建了平滑的并行处理。
分支来自底层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-ti-use-an-assignment-in-an-expression.htm
if (foo = 'bar')在测试的值时犯了这个错误foo。
=
不,BDFL不喜欢该功能。
在我的位置上,“终身慈善独裁者”的Guido van Rossum一直在努力使Python尽可能简单。但是,实际上并没有一个设计Python的委员会,而是一个可信赖的“顾问委员会”,它实际上是基于优点,通过一个设计师的敏感性进行过滤,这一事实产生了一种很好的语言,恕我直言。
if let当我拥有if elif链时,我真的很想念有rust的东西,但是在每种情况下都需要存储和使用条件的值。
按照我的这个老食谱,不是直接的-但正如食谱所说的,构建语义等效项很容易,例如,如果您需要直接从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
顺便说一句,对于您的特定情况,这是一种非常惯用的Python形式,如果您确切知道somefunc在返回虚假值(例如0)时可能返回的虚假值是
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
是的,但仅适用于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中的赋值是语句,而不是表达式。
由于Python的3.8新功能将有可能做到从这个版本这样的事情,虽然没有使用=,但阿达般的赋值运算符:=。来自文档的示例:
# Handle a matched regex
if (match := pattern.search(data)) is not None:
# Do something with match
在某些情况下分配是非法的原因之一是更容易犯错误并分配True或False:
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是关键字,因此不再存在风险。
== True右边。
赋值运算符-也非正式地称为海象运算符-于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)*