Один и тот же ответ на два вопроса не означает, что они дублируются. Нетривиально ответить самому себе, но нетривиально понять аргументы или если есть способ обойти эту проблему.
Мехмет
Ответы:
111
Почему бы не попробовать?
>>> defsome_func():... return2... >>> a = 2>>> if (a = some_func()):
File "<stdin>", line 1if (a = some_func()):
^
SyntaxError: invalid syntax
>>>
это намеренно запрещено, поскольку Гвидо, доброжелательный диктатор питонов, считает их ненужными и более запутывающими, чем полезными. По той же причине нет операторов пост-инкремента или пре-инкремента (++).
Мэтт Бём
4
он позволяет добавлять дополненную распайку в 2.0 , потому что x = x + 1требует дополнительного времени поиска , когда x += 1был несколько быстрее, но я уверен , что он даже не нравится делать , что много. :-)
wescpy
надеюсь, это скоро станет возможным. Python просто медленно развивается
Ник О'Лай
4
«почему бы не попробовать» - потому что кто знает, каков может быть синтаксис? Может быть, OP попробовал это, и это не сработало, но это не значит, что синтаксис не отличается, или что нет способа сделать это, не предназначенного
Аннотация
Это предложение по созданию способа присвоения переменных в выражении с использованием обозначения NAME: = expr. Добавлено новое исключение TargetScopeError и одно изменение в порядке оценки.
«Беспорядок в PEP 572» был темой сессии Python Language Summit 2018, которую провел благотворительный пожизненный диктатор (BDFL) Гвидо ван Россум. PEP 572 стремится добавить к языку выражения присваивания (или «встроенные присваивания»), но он видел продолжительное обсуждение множества огромных потоков в списке рассылки python-dev - даже после нескольких раундов на python-idea. Эти темы часто были спорными и были явно объемными до такой степени, что многие, вероятно, просто игнорировали их. На саммите Ван Россум сделал обзор предложения по функциям, который он, кажется, склонен принять, но он также хотел обсудить, как избежать такого рода всплесков потоков в будущем.
tz используется только для 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 s
sysconfig.py Вызов fp.readline () в условии while и вызов .match () в строках if делает код более компактным без
что затрудняет понимание.
Ток:
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
Улучшенный:
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-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)
В частности, с циклом while, это может устранить необходимость иметь бесконечный цикл, присваивание и условие. Он также создает плавную параллель между циклом, который просто использует вызов функции в качестве своего условия, и циклом, который использует это как свое условие, но также использует фактическое значение.
Форк Пример из низкоуровневого мира UNIX:
if pid := os.fork():
# Parent codeelse:
# Child code
Обратите внимание, что в Python, в отличие от C, присвоение не может происходить внутри выражений. Программисты на C могут жаловаться на это, но это позволяет избежать распространенного класса проблем, встречающихся в программах на языке C: ввод = в выражении, когда было предназначено ==.
Мне нравится этот ответ, потому что он фактически указывает на то, почему такая «функция» могла быть намеренно исключена из Python. Обучая программированию новичков, я видел, как многие совершали эту ошибку if (foo = 'bar'), намереваясь проверить ценность foo.
Джонатан Кросс
2
@JonathanCross, Эта "функция" фактически будет добавлена в 3.8. Маловероятно, что его можно будет использовать так экономно, как следовало бы - но, по крайней мере, это не простая =
Джон Ла Рой
@JohnLaRooy: Глядя на примеры, я думаю, что фраза "вряд ли будет использоваться так экономно, как следовало бы" была точной; Я обнаружил, что из ~ 10 примеров только два действительно улучшают код. (А именно, в качестве единственного выражения либо в условии while, чтобы избежать дублирования строки или наличия условия цикла в теле, либо в цепочке elif, чтобы избежать вложенности)
Алекси Торхамо
39
Нет, BDFL не понравилась эта функция.
С того места, где я сижу, Гвидо ван Россум, «Доброжелательный диктатор на всю жизнь», изо всех сил старался сохранить Python настолько простым, насколько это возможно. Мы можем спорить с некоторыми из принятых им решений - я бы предпочел, чтобы он сказал: «Нет Но тот факт, что не было комитета, разрабатывающего Python, а вместо этого доверенный «консультативный совет», основанный в основном на заслугах и фильтрующий чувства одного дизайнера, создал чертовски хороший язык, ИМХО.
Просто? Эта функция могла бы упростить часть моего кода, потому что она могла бы сделать его более компактным и, следовательно, более читаемым. Теперь мне нужны две строчки там, где раньше была одна. Я никогда не понимал, почему Python на протяжении многих лет (и часто по очень уважительной причине) отказывался от функций, которые есть у других языков программирования. Особенно эта функция, о которой мы здесь говорим, очень и очень полезна.
Regis май
6
Меньше кода не всегда проще или легче читать. Возьмем, к примеру, рекурсивную функцию. Его эквивалент цикла часто более читабелен.
FMF
1
Мне не нравится его C-версия, но мне очень не хватает чего-то вроде rust, if letкогда у меня есть цепочка if elif, но мне нужно хранить и использовать значение условия в каждом случае.
Thayne
1
Я должен сказать, что код, который я пишу сейчас (причина, по которой я искал эту проблему), НАМНОГО уродливее без этой функции. Вместо того, чтобы использовать if, за которым следует множество else if, мне нужно сохранить отступ следующего if под последним else.
MikeKulls
17
Не напрямую, в соответствии с моим старым рецептом, но, как говорится в рецепте, семантический эквивалент легко построить, например, если вам нужно выполнить транслитерацию непосредственно из ссылочного алгоритма с кодировкой C (конечно, перед рефакторингом на более идиоматический Python; -). Т.е.:
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
Кстати, очень идиоматическая питоническая форма для вашего конкретного случая, если вы точно знаете, какое ложное значение 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
но вы можете предпочесть простой настраиваемый генератор:
defgetwhile(func, *a, **k):whileTrue:
x = func(*a, **k)
ifnot x: breakyield x
for a in getwhile(somefunc):
# use a
Я бы проголосовал за это дважды, если бы мог. Это отличное решение для тех времен, когда что-то подобное действительно необходимо. Я адаптировал ваше решение к классу Matcher регулярных выражений, экземпляр которого создается один раз, а затем .check () используется в операторе if, а .result () используется внутри его тела для получения совпадения, если оно было. Благодарность! :)
Teekin
16
Да, но только начиная с Python 3.8 и новее.
PEP 572 предлагает выражения присваивания и уже был принят.
# 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 этот парень был прав гораздо чаще, чем ошибался. Я ценю, что наличие одного человека, отвечающего за видение, приводит к гораздо более согласованной стратегии, чем разработка комитетом; Я могу сравнивать и противопоставлять C ++, который является моим основным хлебом с маслом.
Марк Рэнсом
Я чувствую, что и Ruby, и Scala (на разных языках) лучше понимают это, чем python: но в любом случае здесь не место ..
Стивен Бош
4
Благодаря новой функции Python 3.8 в этой версии можно будет делать это, хотя и не с использованием =оператора присваивания, похожего на Ada :=. Пример из документов:
# Handle a matched regexif (match := pattern.search(data)) isnotNone:
# 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.xTrue = some_variable
printTrue# returns 5
В Python 3 True и False - ключевые слова, так что больше никакого риска.
Ответы:
Почему бы не попробовать?
>>> def some_func(): ... return 2 ... >>> a = 2 >>> if (a = some_func()): File "<stdin>", line 1 if (a = some_func()): ^ SyntaxError: invalid syntax >>>
Так что нет.
Обновление: это возможно (с другим синтаксисом) в Python 3.8
источник
x = x + 1
требует дополнительного времени поиска , когдаx += 1
был несколько быстрее, но я уверен , что он даже не нравится делать , что много. :-)ОБНОВЛЕНИЕ - исходный ответ находится внизу
Python 3.8 принесет PEP572
https://lwn.net/Articles/757713/
https://www.python.org/dev/peps/pep-0572/#examples-from-the-python-standard-library
Оригинальный ответ
http://docs.python.org/tutorial/datastructures.html
также см:
http://effbot.org/pyfaq/why-can-ti-use-an-assignment-in-an-expression.htm
источник
if (foo = 'bar')
, намереваясь проверить ценностьfoo
.=
Нет, BDFL не понравилась эта функция.
С того места, где я сижу, Гвидо ван Россум, «Доброжелательный диктатор на всю жизнь», изо всех сил старался сохранить Python настолько простым, насколько это возможно. Мы можем спорить с некоторыми из принятых им решений - я бы предпочел, чтобы он сказал: «Нет Но тот факт, что не было комитета, разрабатывающего Python, а вместо этого доверенный «консультативный совет», основанный в основном на заслугах и фильтрующий чувства одного дизайнера, создал чертовски хороший язык, ИМХО.
источник
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
Кстати, очень идиоматическая питоническая форма для вашего конкретного случая, если вы точно знаете, какое ложное значение
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 в этой версии можно будет делать это, хотя и не с использованием
=
оператора присваивания, похожего на 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)
источник
Одна из причин, по которой присваивания недопустимы в условиях, заключается в том, что легче ошибиться и присвоить 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
все равно выбирают правильную сторону.Оператор присваивания, также неофициально известный как оператор моржа, был создан 28 февраля 2018 г. в 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)*
источник