条件付きでの割り当ては可能ですか?
例:
if (a=some_func()):
# Use a
回答:
試してみませんか?
>>> 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がいくらか高速であるため、追加のルックアップ時間が必要なためですが、彼はそれほど多くのことをするのが好きではなかったと確信しています。:-)
要約
これは、NAME:= exprという表記を使用して式内の変数に割り当てる方法を作成するための提案です。新しい例外TargetScopeErrorが追加され、評価順序が1つ変更されました。
https://lwn.net/Articles/757713/
「PEP572混乱」は、慈悲深き独裁者(BDFL)のグイドヴァンロッサムが率いる2018年のPython言語サミットセッションのトピックでした。PEP 572は、言語に代入式(または「インライン代入」)を追加しようとしますが、python-ideasで複数回ラウンドした後でも、python-devメーリングリストの複数の巨大なスレッドについて長い議論がありました。それらのスレッドはしばしば論争を呼んでおり、多くの人がおそらくそれらを調整したところまで明らかにボリュームがありました。サミットでは、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ネストされた場合は避け、1つのインデントレベルを削除します。
電流:
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。
=
a if a := 1 == 1 else False→ Invalid syntax:cしたがって、明らかにまだ古い厄介なことに頼る必要があります(lambda: (ret := foo(), ret if ret else None))()[-1] (つまりfoo()、三元での繰り返しの呼び出しを回避する方法として)。
いいえ、BDFLはその機能が気に入らなかった。
私が座っているところから、Guido vanRossumの「BenevolentDictatorFor Life」は、Pythonを可能な限りシンプルに保つために懸命に戦ってきました。彼が下した決定のいくつかに疑問を投げかけることができます。 'より頻繁に。しかし、Pythonを設計する委員会がなく、代わりに、主にメリットに基づいて、1人の設計者の感性をフィルタリングする信頼できる「諮問委員会」があったという事実は、素晴らしい言語の1つの地獄であるIMHOを生み出しました。
if letが、if elifチェーンがあると、錆のようなものが本当に恋しいですが、それぞれの場合に条件の値を保存して使用する必要があります。
直接ではありませんが、私のこの古いレシピによると、レシピにあるように、セマンティックに相当するものを簡単に構築できます。たとえば、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
はい。ただし、Python3.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の新機能のおかげで=、Adaのような代入演算子を使用していなくても、このバージョンからそのようなことを行うことが可能になります:=。ドキュメントからの例:
# Handle a matched regex
if (match := pattern.search(data)) is not None:
# Do something with match
割り当てを行う関数を定義できます。
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)
条件で割り当てが違法である理由の1つは、間違いを犯して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)*