Подтвердить что ты не робот

Можем ли мы иметь назначение в состоянии?

Возможно ли иметь назначение в условии?

Например,

if (a=some_func()):
    # Use a
4b9b3361

Ответ 1

Почему бы не попробовать?

>>> def some_func():
...   return 2
... 
>>> a = 2
>>> if (a = some_func()):
  File "<stdin>", line 1
    if (a = some_func()):
          ^
SyntaxError: invalid syntax
>>> 

Итак, нет.

Ответ 2

Нет, BDFL не понравилась эта функция.

С того места, где я сижу, Гвидо ван Россум, "Доброжелательный диктатор для жизни", изо всех сил старался держать Python настолько простым, насколько это возможно. Мы можем спорить с некоторыми из решений, которые он принял - я бы предпочел, чтобы он сказал "Нет" чаще. Но тот факт, что не был комитет, проектирующий Python, а вместо этого доверенный "консультативный совет", основанный в основном на заслугах, фильтруя через одну дизайнерскую чувствительность, произвел один адский приятный язык, ИМХО.

Ответ 3

ОБНОВЛЕНИЕ - Оригинальный ответ в нижней части

Python 3.8 принесет PEP572

Аннотация
Это предложение по созданию способа присваивания переменным в выражении с использованием обозначения NAME: = expr. Добавлено новое исключение TargetScopeError, и есть одно изменение в порядке оценки.

https://lwn.net/Articles/757713/

"Беспорядок в PEP 572" был темой заседания на высшем уровне по языку Python 2018 года, которое провел доброжелательный диктатор на всю жизнь (BDFL) Гидо ван Россум. PEP 572 стремится добавить выражения присваивания (или "встроенные присваивания") к языку, но он видел длительное обсуждение нескольких огромных потоков в списке рассылки python-dev - даже после нескольких раундов по идеям python. Эти темы часто были спорными и явно объемными до такой степени, что многие, вероятно, только что отключили их. На саммите Ван Россум представил обзор предложения, которое он, похоже, склонен принять, но он также хотел обсудить, как избежать такого взрыва потока в будущем.

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

Избегайте вложенных if и удалите один уровень отступа.

Текущий:

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 ans

copy.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.py

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 делают код более компактным без

затрудняя понимание.

Текущий:

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

Ответ 4

Не прямо, за этот старый рецепт моего - но, как говорится в рецепте, легко построить семантический эквивалент, например. если вам нужно транслитерировать непосредственно из 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

BTW, очень идиоматическая питоническая форма для вашего конкретного случая, если вы точно знаете, какое значение falsish somefunc может вернуться, когда оно вернет значение falsish (например, 0),

for a in iter(somefunc, 0):
  # use a

поэтому в этом конкретном случае рефакторинг будет довольно простым; -).

Если возврат может быть любым значением фальшивого значения (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

Ответ 5

Да, но только с 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 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

Ответ 6

Нет. Назначение в Python - это выражение, а не выражение.

Ответ 7

Благодаря новой функции Python 3.8 это можно будет сделать из этой версии, хотя и без использования = но с помощью Ada-подобного оператора присваивания :=. Пример из документов:

# Handle a matched regex
if (match := pattern.search(data)) is not None:
    # Do something with match

Ответ 8

Вы можете определить функцию для назначения для вас:

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)

Ответ 9

Одна из причин, по которой присвоения являются незаконными в условиях, заключается в том, что проще совершить ошибку и назначить 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 являются ключевыми словами, поэтому больше никакого риска.