Czy można mieć przydział w stanie?
Na przykład.
if (a=some_func()):
# Use a
Odpowiedzi:
Dlaczego by tego nie wypróbować?
>>> def some_func():
... return 2
...
>>> a = 2
>>> if (a = some_func()):
File "<stdin>", line 1
if (a = some_func()):
^
SyntaxError: invalid syntax
>>>
Więc nie.
Aktualizacja: jest to możliwe (z inną składnią) w Pythonie 3.8
x = x + 1wymaga dodatkowego czasu wyszukiwania, podczas gdy x += 1był nieco szybszy, ale jestem pewien, że nawet nie lubił robić tak dużo. :-)
Python 3.8 przyniesie PEP572
Abstrakt
To jest propozycja stworzenia sposobu przypisywania zmiennych w wyrażeniu przy użyciu notacji NAZWA: = wyrażenie. Dodano nowy wyjątek TargetScopeError i nastąpiła jedna zmiana w kolejności oceny.
https://lwn.net/Articles/757713/
„Bałagan PEP 572” był tematem sesji szczytu języka Python w 2018 roku prowadzonej przez życzliwego dyktatora życia (BDFL) Guido van Rossuma. PEP 572 stara się dodać wyrażenia przypisania (lub „przypisania w wierszu”) do języka, ale widział długotrwałą dyskusję na temat wielu dużych wątków na liście mailingowej python-dev - nawet po wielu rundach poświęconych pomysłom na Pythona. Wątki te były często kontrowersyjne i wyraźnie obszerne do tego stopnia, że wielu prawdopodobnie po prostu je wyciszyło. Na szczycie Van Rossum przedstawił przegląd propozycji funkcji, którą wydaje się być skłonny zaakceptować, ale chciał też omówić, jak uniknąć tego rodzaju eksplozji wątków w przyszłości.
https://www.python.org/dev/peps/pep-0572/#examples-from-the-python-standard-library
Przykłady ze standardowej biblioteki Pythona
site.py env_base jest używane tylko w tych wierszach, umieszczenie jego przypisania na if przesuwa go jako "nagłówek" bloku.
Obecny:
env_base = os.environ.get("PYTHONUSERBASE", None) if env_base: return env_baseUlepszony:
if env_base := os.environ.get("PYTHONUSERBASE", None): return env_base _pydecimal.pyUnikaj zagnieżdżania if i usuń jeden poziom wcięcia.
Obecny:
if self._is_special: ans = self._check_nans(context=context) if ans: return ansUlepszony:
if self._is_special and (ans := self._check_nans(context=context)): return anscopy.py Kod wygląda na bardziej regularny i unikaj wielokrotnego zagnieżdżania if. (Zobacz dodatek A, aby zapoznać się z pochodzeniem tego przykładu).
Obecny:
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)Ulepszony:
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 jest używane tylko dla s + = tz, przeniesienie jego przypisania wewnątrz if pomaga pokazać jego zasięg.
Obecny:
s = _format_time(self._hour, self._minute, self._second, self._microsecond, timespec) tz = self._tzstr() if tz: s += tz return sUlepszony:
s = _format_time(self._hour, self._minute, self._second, self._microsecond, timespec) if tz := self._tzstr(): s += tz return ssysconfig.py Wywołanie fp.readline () w warunku while i wywołanie .match () w liniach if sprawia, że kod jest bardziej zwarty bez
utrudniając zrozumienie.
Obecny:
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)] = 0Ulepszony:
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)] = 0Upraszczanie składanych list Funkcja rozumienia list może skutecznie mapować i filtrować, przechwytując warunek:
results = [(x, y, x/y) for x in input_data if (y := f(x)) > 0]Podobnie podwyrażenie można ponownie wykorzystać w wyrażeniu głównym, nadając mu nazwę przy pierwszym użyciu:
stuff = [[y := f(x), x/y] for x in range(5)]Zauważ, że w obu przypadkach zmienna y jest związana w zakresie zawierającym (tj. Na tym samym poziomie co wyniki lub rzeczy).
Przechwytywanie wartości warunków Wyrażenia przypisania mogą być używane z dobrym skutkiem w nagłówku instrukcji if lub 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)Szczególnie w przypadku pętli while może to wyeliminować potrzebę posiadania nieskończonej pętli, przypisania i warunku. Tworzy również płynną paralelę między pętlą, która po prostu używa wywołania funkcji jako warunku, a taką, która używa tego jako warunku, ale także używa rzeczywistej wartości.
Fork Przykład z niskiego poziomu świata UNIX:
if pid := os.fork(): # Parent code else: # Child code
http://docs.python.org/tutorial/datastructures.html
Zauważ, że w Pythonie, w przeciwieństwie do C, przypisanie nie może występować wewnątrz wyrażeń. Programiści C mogą narzekać na to, ale pozwala to uniknąć typowej klasy problemów napotykanych w programach C: wpisanie = w wyrażeniu, gdy zamierzano ==.
Zobacz także:
http://effbot.org/pyfaq/why-can-ti-use-an-assignment-in-an-expression.htm
if (foo = 'bar'), zamierzając przetestować wartość foo.
=
Nie, BDFL nie lubił tej funkcji.
Z miejsca, w którym siedzę, Guido van Rossum, „Benevolent Dictator For Life”, ciężko walczył, aby Python był tak prosty, jak to tylko możliwe. Możemy spierać się o niektóre decyzje, które podjął - wolałbym, żeby powiedział „Nie Ale fakt, że nie było komitetu projektującego Pythona, ale zamiast tego zaufana „rada doradcza”, oparta w dużej mierze na zasługach, filtrująca wrażliwość jednego projektanta, zaowocował cholernie przyjemnym językiem, IMHO.
if letgdy mam łańcuch if elif, ale muszę przechowywać i używać wartości warunku w każdym przypadku.
Nie bezpośrednio, zgodnie z moim starym przepisem - ale jak mówi przepis, łatwo jest zbudować semantyczny odpowiednik, np. Jeśli potrzebujesz transliteracji bezpośrednio z algorytmu referencyjnego zakodowanego w C (przed refaktoryzacją do bardziej idiomatycznego Pythona, oczywiście; -). To znaczy:
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, bardzo idiomatyczna forma Pythona dla twojego konkretnego przypadku, jeśli wiesz dokładnie, jaka fałszywa wartość somefuncmoże zwrócić, gdy zwraca fałszywą wartość (np. 0), Jest
for a in iter(somefunc, 0):
# use a
więc w tym konkretnym przypadku refaktoryzacja byłaby całkiem prosta ;-).
Jeśli zysk może być dowolny rodzaj wartości falsish (0, None, '', ...), jedną z możliwości jest:
import itertools
for a in itertools.takewhile(lambda x: x, iter(somefunc, object())):
# use a
ale możesz preferować prosty generator niestandardowy:
def getwhile(func, *a, **k):
while True:
x = func(*a, **k)
if not x: break
yield x
for a in getwhile(somefunc):
# use a
Tak, ale tylko od wersji Python 3.8 i nowszych.
PEP 572 proponuje wyrażenia przypisania i został już zaakceptowany.
Cytując składnię i semantykę części 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]
W swoim konkretnym przypadku będziesz mógł pisać
if a := some_func():
# Use a
Nie. Przypisanie w Pythonie jest instrukcją, a nie wyrażeniem.
Dzięki nowej funkcji Pythona 3.8 będzie można zrobić coś takiego z poziomu tej wersji, choć nie używając =tylko operatora przypisania w stylu Ada :=. Przykład z dokumentów:
# Handle a matched regex
if (match := pattern.search(data)) is not None:
# Do something with match
Możesz zdefiniować funkcję, która będzie wykonywać przypisywanie za Ciebie:
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)
Jednym z powodów, dla których przypisania są nielegalne w warunkach, jest to, że łatwiej jest popełnić błąd i przypisać Prawdę lub Fałsz:
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
W Pythonie 3 True i False to słowa kluczowe, więc nie ma już żadnego ryzyka.
== Truena właściwą stronę.
Operator przypisania - znany również nieformalnie jako operator morsa - został utworzony 28 lutego 2018 r. W PEP572 .
Ze względu na kompletność opublikuję odpowiednie części, abyś mógł porównać różnice między 3.7 i 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)*