To, że dwa pytania mają tę samą odpowiedź, nie oznacza, że są duplikatami. Trywialne, aby odpowiedzieć sobie, ale nie jest to trywialne, aby zobaczyć uzasadnienie lub jeśli jest na to sposób.
mehmet
Odpowiedzi:
111
Dlaczego by tego nie wypróbować?
>>> defsome_func():... return2... >>> a = 2>>> if (a = some_func()):
File "<stdin>", line 1if (a = some_func()):
^
SyntaxError: invalid syntax
>>>
jest to celowo zabronione, ponieważ Guido, życzliwy dyktator pytonów, uważa je za niepotrzebne i bardziej zagmatwane niż przydatne. Z tego samego powodu nie ma operatorów post-inkrementacyjnych ani preinkrementacyjnych (++).
Matt Boehm
4
zezwolił na dodanie rozszerzonego przypisania w wersji 2.0, ponieważ x = x + 1wymaga dodatkowego czasu wyszukiwania, podczas gdy x += 1był nieco szybszy, ale jestem pewien, że nawet nie lubił robić tak dużo. :-)
wescpy
mam nadzieję, że wkrótce stanie się to możliwe. Python ewoluuje powoli
Nik O'Lai
4
„dlaczego by tego nie wypróbować” - bo kto wie, jaka może być składnia? Może OP spróbował tego i nie zadziałało, ale to nie znaczy, że składnia nie jest inna lub że nie ma sposobu, aby to zrobić, który nie jest przeznaczony
Levi H
57
AKTUALIZACJA - Oryginalna odpowiedź znajduje się na dole
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.
„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.
tz 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 s
Ulepszony:
s = _format_time(self._hour, self._minute,
self._second, self._microsecond,
timespec)
if tz := self._tzstr():
s += tz
return s
sysconfig.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:
whileTrue:
line = fp.readline()
ifnot 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
Ulepszony:
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
Upraszczanie 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-halfwhile (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 effectif 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 returnedwhile 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 codeelse:
# Child code
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 ==.
Podoba mi się ta odpowiedź, ponieważ tak naprawdę wskazuje, dlaczego taka „funkcja” mogła zostać celowo pominięta w Pythonie. Podczas nauczania programowania dla początkujących widziałem, jak wielu popełnia ten błąd if (foo = 'bar'), zamierzając przetestować wartość foo.
Jonathan Cross
2
@JonathanCross, Ta „funkcja” zostanie dodana w wersji 3.8. Jest mało prawdopodobne, aby był używany tak oszczędnie, jak powinien - ale przynajmniej nie jest to zwykły=
John La Rooy,
@JohnLaRooy: Patrząc na przykłady, myślę, że „mało prawdopodobne, by był używany tak oszczędnie, jak powinien” był trafiony; Z ~ 10 przykładów stwierdzam, że tylko dwa poprawiają kod. (Mianowicie, jako jedyne wyrażenie albo w stanie while, aby uniknąć powielania linii lub stanu pętli w ciele lub w łańcuchu elif, aby uniknąć zagnieżdżenia)
Aleksi Torhamo
39
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.
Prosty? Ta funkcja mogłaby uprościć całkiem część mojego kodu, ponieważ mogłaby uczynić go bardziej zwartym i przez to bardziej czytelnym. Teraz potrzebuję dwóch wierszy, w których kiedyś potrzebowałem. Nigdy nie zrozumiałem, dlaczego Python odrzucał funkcje, które inne języki programowania mają przez wiele lat (i często z bardzo dobrego powodu). Szczególnie ta funkcja, o której tutaj mówimy, jest bardzo, bardzo przydatna.
Regis,
6
Mniej kodu nie zawsze jest prostsze lub czytelne w morde. Weźmy na przykład funkcję rekurencyjną. To odpowiednik pętli jest często bardziej czytelny.
FMF
1
Nie podoba mi się wersja C tego, ale naprawdę brakuje mi czegoś takiego jak rdza, if letgdy mam łańcuch if elif, ale muszę przechowywać i używać wartości warunku w każdym przypadku.
Thayne
1
Muszę powiedzieć, że kod, który teraz piszę (powód, dla którego przeszukałem ten numer) jest DUŻO brzydszy bez tej funkcji. Zamiast używać if, po którym następuje wiele else ifs, muszę nadal wciskać następny if pod ostatnim else.
MikeKulls
17
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:
classDataHolder(object):def__init__(self, value=None): self.value = value
defset(self, value): self.value = value; return value
defget(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:
defgetwhile(func, *a, **k):whileTrue:
x = func(*a, **k)
ifnot x: breakyield x
for a in getwhile(somefunc):
# use a
Gdybym mógł, zagłosowałbym dwukrotnie. To świetne rozwiązanie na czasy, kiedy coś takiego jest naprawdę potrzebne. Zaadaptowałem Twoje rozwiązanie do klasy regex Matcher, która jest tworzona raz, a następnie .check () jest używana w instrukcji if i .result () używanej wewnątrz jej treści w celu pobrania dopasowania, jeśli taki istnieje. Dzięki! :)
Teekin
16
Tak, ale tylko od wersji Python 3.8 i nowszych.
PEP 572 proponuje wyrażenia przypisania i został już zaakceptowany.
# Handle a matched regexif (match := pattern.search(data)) isnotNone:
# 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)) isnotNone]
@javadba facet miał rację znacznie częściej niż mylił się. Doceniam, że posiadanie jednej osoby odpowiedzialnej za wizję skutkuje dużo bardziej spójną strategią niż projekt komitetu; Potrafię porównać i kontrastować z C ++, który jest moim głównym tematem.
Mark Ransom
Czuję, że zarówno ruby, jak i scala (w różnych językach) robią to dobrze znacznie bardziej niż python: ale w każdym razie tutaj nie ma miejsca ..
StephenBoesch
4
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 regexif (match := pattern.search(data)) isnotNone:
# Do something with match
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.xTrue = some_variable
printTrue# returns 5
W Pythonie 3 True i False to słowa kluczowe, więc nie ma już żadnego ryzyka.
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
źródło
x = x + 1
wymaga dodatkowego czasu wyszukiwania, podczas gdyx += 1
był nieco szybszy, ale jestem pewien, że nawet nie lubił robić tak dużo. :-)AKTUALIZACJA - Oryginalna odpowiedź znajduje się na dole
Python 3.8 przyniesie PEP572
https://lwn.net/Articles/757713/
https://www.python.org/dev/peps/pep-0572/#examples-from-the-python-standard-library
Oryginalna odpowiedź
http://docs.python.org/tutorial/datastructures.html
Zobacz także:
http://effbot.org/pyfaq/why-can-ti-use-an-assignment-in-an-expression.htm
źródło
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.
źródło
if let
gdy 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ść
somefunc
może zwrócić, gdy zwraca fałszywą wartość (np.0
), Jestfor 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
źródło
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
źródło
Nie. Przypisanie w Pythonie jest instrukcją, a nie wyrażeniem.
źródło
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
źródło
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)
źródło
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.
źródło
== True
na 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)*
źródło