Ist es möglich, eine Zuordnung in einem Zustand zu haben?
Zum Beispiel.
if (a=some_func()):
# Use a
Ist es möglich, eine Zuordnung in einem Zustand zu haben?
Zum Beispiel.
if (a=some_func()):
# Use a
Antworten:
Warum probieren Sie es nicht aus?
>>> def some_func():
... return 2
...
>>> a = 2
>>> if (a = some_func()):
File "<stdin>", line 1
if (a = some_func()):
^
SyntaxError: invalid syntax
>>>
Also nein.
Update: Dies ist (mit unterschiedlicher Syntax) in Python 3.8 möglich
x = x + 1erfordert zusätzliche Lookup - Zeit , während x += 1etwas schneller war, aber ich bin sicher , hat er nicht einmal , wie zu tun , dass viel. :-)
Python 3.8 bringt PEP572
Zusammenfassung
Dies ist ein Vorschlag zum Erstellen einer Möglichkeit zum Zuweisen von Variablen innerhalb eines Ausdrucks unter Verwendung der Notation NAME: = Ausdruck. Eine neue Ausnahme, TargetScopeError, wurde hinzugefügt, und die Auswertungsreihenfolge wurde geändert.
https://lwn.net/Articles/757713/
Das "PEP 572-Durcheinander" war das Thema einer Sitzung des Python Language Summit 2018, die von dem wohlwollenden Diktator für das Leben (BDFL) Guido van Rossum geleitet wurde. PEP 572 versucht, der Sprache Zuweisungsausdrücke (oder "Inline-Zuweisungen") hinzuzufügen, hat jedoch eine längere Diskussion über mehrere große Threads auf der Python-Dev-Mailingliste gesehen - selbst nach mehreren Runden mit Python-Ideen. Diese Threads waren oft umstritten und eindeutig so umfangreich, dass viele sie wahrscheinlich gerade ausgeschaltet haben. Auf dem Gipfel gab Van Rossum einen Überblick über den Feature-Vorschlag, den er offenbar gerne annimmt, wollte aber auch diskutieren, wie diese Art von Fadenexplosion in Zukunft vermieden werden kann.
https://www.python.org/dev/peps/pep-0572/#examples-from-the-python-standard-library
Beispiele aus der Python-Standardbibliothek
site.py env_base wird nur in diesen Zeilen verwendet und setzt seine Zuweisung auf das if, wenn es als "Header" des Blocks verschoben wird.
Aktuell:
env_base = os.environ.get("PYTHONUSERBASE", None) if env_base: return env_baseVerbessert:
if env_base := os.environ.get("PYTHONUSERBASE", None): return env_base _pydecimal.pyVermeiden Sie verschachtelte if und entfernen Sie eine Einrückungsstufe.
Aktuell:
if self._is_special: ans = self._check_nans(context=context) if ans: return ansVerbessert:
if self._is_special and (ans := self._check_nans(context=context)): return anscopy.py Code sieht regelmäßiger aus und vermeidet mehrfach verschachtelte if. (Die Herkunft dieses Beispiels finden Sie in Anhang A.)
Aktuell:
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)Verbessert:
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 wird nur für s + = tz verwendet, wobei die Zuordnung innerhalb des if verschoben wird, um den Umfang anzuzeigen.
Aktuell:
s = _format_time(self._hour, self._minute, self._second, self._microsecond, timespec) tz = self._tzstr() if tz: s += tz return sVerbessert:
s = _format_time(self._hour, self._minute, self._second, self._microsecond, timespec) if tz := self._tzstr(): s += tz return ssysconfig.py Wenn Sie fp.readline () in der while-Bedingung aufrufen und .match () in den if-Zeilen aufrufen, wird der Code ohne kompakter
macht es schwieriger zu verstehen.
Aktuell:
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)] = 0Verbessert:
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)] = 0Vereinfachen des Listenverständnisses Ein Listenverständnis kann effizient erfasst und gefiltert werden, indem die Bedingung erfasst wird:
results = [(x, y, x/y) for x in input_data if (y := f(x)) > 0]Ebenso kann ein Unterausdruck innerhalb des Hauptausdrucks wiederverwendet werden, indem ihm bei der ersten Verwendung ein Name gegeben wird:
stuff = [[y := f(x), x/y] for x in range(5)]Beachten Sie, dass in beiden Fällen die Variable y im enthaltenden Bereich gebunden ist (dh auf derselben Ebene wie Ergebnisse oder Material).
Erfassen von Bedingungswerten Zuweisungsausdrücke können im Header einer if- oder while-Anweisung effektiv verwendet werden:
# 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)Insbesondere bei der while-Schleife kann dies die Notwendigkeit einer Endlosschleife, einer Zuweisung und einer Bedingung beseitigen. Es wird auch eine glatte Parallele zwischen einer Schleife erstellt, die einfach einen Funktionsaufruf als Bedingung verwendet, und einer Schleife, die diesen als Bedingung verwendet, aber auch den tatsächlichen Wert verwendet.
Gabel Ein Beispiel aus der UNIX-Welt auf niedriger Ebene:
if pid := os.fork(): # Parent code else: # Child code
http://docs.python.org/tutorial/datastructures.html
Beachten Sie, dass in Python im Gegensatz zu C die Zuweisung nicht innerhalb von Ausdrücken erfolgen kann. C-Programmierer mögen darüber meckern, aber es vermeidet eine häufige Klasse von Problemen, die in C-Programmen auftreten: Geben Sie = in einen Ausdruck ein, wenn == beabsichtigt war.
siehe auch:
http://effbot.org/pyfaq/why-can-ti-use-an-assignment-in-an-expression.htm
if (foo = 'bar')als sie beabsichtigten, den Wert von zu testen foo.
=
Nein, die BDFL mochte diese Funktion nicht.
Von meinem Platz aus hat Guido van Rossum, "Wohlwollender Diktator fürs Leben", hart dafür gekämpft, Python so einfach wie möglich zu halten. Wir können uns mit einigen seiner Entscheidungen streiten - ich hätte es vorgezogen, wenn er "Nein" gesagt hätte Aber die Tatsache, dass es kein Komitee gab, das Python entwarf, sondern einen vertrauenswürdigen "Beirat", der größtenteils auf Verdiensten basiert und die Sensibilität eines Designers filtert, hat meiner Meinung nach eine verdammt schöne Sprache hervorgebracht, IMHO.
if letwenn ich eine If-Elif-Kette habe, aber ich muss den Wert der Bedingung in jedem Fall speichern und verwenden.
Nicht direkt nach diesem alten Rezept von mir - aber wie das Rezept sagt, ist es einfach, das semantische Äquivalent zu erstellen, z. B. wenn Sie direkt von einem C-codierten Referenzalgorithmus transliterieren müssen (natürlich vor dem Refactoring zu mehr idiomatischem Python; -). Dh:
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
Übrigens, eine sehr idiomatische pythonische Form für Ihren speziellen Fall, wenn Sie genau wissen, welcher falsche Wert zurückkehren somefunckann, wenn er einen falschen Wert zurückgibt (z. B. 0)
for a in iter(somefunc, 0):
# use a
in diesem speziellen Fall wäre das Refactoring also ziemlich einfach ;-).
Wenn die Rückkehr könnte jede Art von falsish Wert (0, None, '', ...), eine Möglichkeit ist:
import itertools
for a in itertools.takewhile(lambda x: x, iter(somefunc, object())):
# use a
Möglicherweise bevorzugen Sie jedoch einen einfachen benutzerdefinierten Generator:
def getwhile(func, *a, **k):
while True:
x = func(*a, **k)
if not x: break
yield x
for a in getwhile(somefunc):
# use a
Ja, aber nur ab Python 3.8.
PEP 572 schlägt Zuweisungsausdrücke vor und wurde bereits akzeptiert.
Zitieren des Syntax- und Semantikteils des 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]
In Ihrem speziellen Fall können Sie schreiben
if a := some_func():
# Use a
Die Zuweisung in Python ist eine Anweisung, kein Ausdruck.
Dank der neuen Funktion von Python 3.8 wird es möglich sein, so etwas ab dieser Version zu tun, obwohl nicht der =Ada-ähnliche Zuweisungsoperator verwendet wird :=. Beispiel aus den Dokumenten:
# Handle a matched regex
if (match := pattern.search(data)) is not None:
# Do something with match
Sie können eine Funktion definieren, die die Zuweisung für Sie übernimmt:
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)
Einer der Gründe, warum Zuweisungen unter bestimmten Bedingungen illegal sind, besteht darin, dass es einfacher ist, einen Fehler zu machen und Richtig oder Falsch zuzuweisen:
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
In Python 3 sind Wahr und Falsch Schlüsselwörter, also kein Risiko mehr.
== Truesowieso auf die richtige Seite gehen.
Der Zuweisungsoperator - auch informell als Walrossoperator bezeichnet - wurde am 28. Februar 2018 in PEP572 erstellt .
Der Vollständigkeit halber werde ich die relevanten Teile veröffentlichen, damit Sie die Unterschiede zwischen 3.7 und 3.8 vergleichen können:
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)*