Выражение присваивания (также известное как оператор walrus) — это функциональность, которая появилась в Python недавно, в версии 3.8. Однако применение walrus является предметом дискуссий и множество людей испытывают безосновательную неприязнь к нему.

Под катом эксперт компании IBM Мартин Хайнц*, разработчик и DevOps-инженер, постарается убедить вас в том, что оператор walrus — действительно хорошее дополнение языка. И его правильное использование поможет вам сделать код более лаконичным и читаемым.

*Обращаем ваше внимание, что позиция автора может не всегда совпадать с мнением МойОфис.


Рассмотрим основы

Если вы вдруг не знакомы с моржовым оператором := (walrus), давайте для начала рассмотрим некоторые основные случаи его использования.

В первом примере я покажу вам, как можно использовать оператор walrus, чтобы сократить количество вызовов функции.

Давайте представим функцию func(), которая производит какие-то очень ресурсоемкие расчеты. Она требует много времени для вычисления результатов, поэтому мы не хотим вызывать ее многократно:

# "func" вызывает трижды
result = [func(x), func(x)**2, func(x)**3]

# Переиспользуем результат функции без разделения кода на несколько строк
result = [y := func(x), y**2, y**3]

В первой форме объявления списка, func(x) вызывается трижды, каждый раз возвращая один и тот же результат, который каждый раз тратил ресурсы вычислительной машины. Когда мы перепишем выражение с использованием оператора walrus, func() будет вызвана только один раз, присваивая результат вычисления y и повторно используя значение для оставшихся двух элементов списка. Вы можете сказать "Просто добавь y = func(x) перед объявлением списка и тебе не понадобится оператор walrus!". Можно так сделать, но для этого потребуется еще одна дополнительная строка кода и, на первый взгляд, без знания о том, что func(x) очень медленная, может быть неясно, зачем эта переменная нужна.

Если первый пример не убедил вас, вот еще один. Рассмотрим следующие способы объявления списка тоже с ресурсоемкой func():

result = [func(x) for x in data if func(x)]
result = [y for x in data if (y := func(x))]

В первой строке func(x) вызывается дважды в каждой итерации. Альтернатива — использовать оператор walrus. Значение рассчитывается однократно — в условном выражении, и используется повторно. Размер кода тот же, обе строки одинаково читаемые, но на второй строке реализация в два раза эффективнее. Вы можете избежать применения := с сохранением эффективности исполняемого кода путем описания конструкции через обычный цикл, однако для этого потребуется 5 строк кода.

Одно из наиболее типовых применений оператора walrus — в сокращении количества излишних условий, таких как найденные соответствия при использовании регулярных выражений.

import re
test = "Something to match"

pattern1 = r"^.*(thing).*"
pattern2 = r"^.*(not present).*"

m = re.match(pattern1, test)
if m:
    print(f"Matched the 1st pattern: {m.group(1)}")
else:
    m = re.match(pattern2, test)
    if m:
        print(f"Matched the 2nd pattern: {m.group(1)}")

# ---------------------
# Или иначе
if m := (re.match(pattern1, test)):
    print(f"Matched 1st pattern: '{m.group(1)}'")
elif m := (re.match(pattern2, test)):
    print(f"Matched 2nd pattern: '{m.group(1)}'")

Используя walrus мы сократили один и тот же код с 7 до 4 строк, сделав его более читаемым через удаление ненужных if.

Следующий пример — это так называемая идиома "loop-and-half":

while True:  # Loop
    command = input("> ")
    if command == 'exit':  # And a half
        break
    print("Your command was:", command)

# ---------------------
# Или иначе
while (command := input("> ")) != "exit":
    print("Your command was:", command)

Обычное решение заключается в использовании бесконечного цикла, в котором управление циклом осуществляется через объявление break. Вместо этого мы можем задействовать оператор walrus, чтобы заново присвоить значение исполненной команды и затем использовать его в условии остановки цикла на той же строке, делая код более явным и коротким.

Простое упрощение может быть применено также к другому циклу, while — например, в случае чтения файлов построчно или получения данных из сокета.

Суммирование данных прямо на месте

Обратимся к более продвинутым примерам использования оператора walrus. В этот раз рассмотрим возможность суммирования данных прямо по месту применения:

data = [5, 4, 3, 2]
c = 0; print([(c := c + x) for x in data])  # c = 14
# [5, 9, 12, 14]

from itertools import accumulate
print(list(accumulate(data)))

# ---------------------
data = [5, 4, 3, 2]
print(list(accumulate(data, lambda a, b: a*b)))
# [5, 20, 60, 120]

a = 1; print([(a := a*b) for b in data])
# [5, 20, 60, 120]

В первых двух строках показано, как можно использовать walrus для расчета суммы значений. В этом простом случае функция accumulate лучше подходит для этой цели (как видно из следующих двух строк). Однако применение itertools с увеличением сложности и объема кода делает его менее читаемым и, по моему мнению, версия с := намного приятнее, чем с lambda.

Если вы все еще не убеждены, посмотрите сводные примеры в документации (например, сложный процент или логистическую карту): они не выглядят читаемыми. Попробуйте переписать их на использование выражения присваивания :=, и они будут смотреться намного лучше.

Именованные значения в f-string

Этот пример показывает возможные случаи и ограничения использования := в сравнении с лучшими практиками.

Если хотите, то можете использовать оператор walrus в f-string:

from datetime import datetime
print(f"Today is: {(today:=datetime.today()):%Y-%m-%d}, which is {today:%A}")
# Today is: 2022-07-01, which is Friday

from math import radians, sin, cos
angle = 60
print(f'{angle=}\N{degree sign} {(theta := radians(angle)) =: .2f}, {sin(theta) =: .2f}, {cos(theta) =: .2f}')
# angle=60° (theta := radians(angle)) = 1.05, sin(theta) = 0.87, cos(theta) = 0.50

В первом выражении print используется := для определения переменной today, которая затем повторно используется на той же строке, предотвращая повторный вызов функции datetime.today().

Похожим образом во втором примере объявлена theta переменная, которая затем используется снова для расчета sin(theta) и cos(theta). В данном случае в выражении также встречается сочетание символов, которое выглядит как "обратный" walrus. Символ = отвечает за вывод выражения на экран, а в связке с : используется для форматированного вывода значения выражения.

Заметим также, что выражение с оператором walrus требует обрамления в скобки, чтобы внутри f-string оно интерпретировалось корректно.

Any и ALL

Можно использовать функции any() и all() для проверки удовлетворения условию любых или всех значений в итерируемом объекте. А что, если вы захотите также значение, которое оставляет any() для возвращаемого значения True (так называемый "свидетель") или же значение, которое не удовлетворило проверке all() (так называемый "контрпример")?

numbers = [1, 4, 6, 2, 12, 4, 15]
# Возвращает только результат логического выражения, не значение
print(any(number > 10 for number in numbers))  # True
print(all(number < 10 for number in numbers))  # False

# ---------------------
any((value := number) > 10 for number in numbers)  # True
print(value)  # 12

all((counter_example := number) < 10 for number in numbers)  # False
print(counter_example)  # 12

Обе функции any() и all() используют короткую схему вычисления результата. Это означает, что они остановят вычисление, как только найдут первого "свидетеля" или "контрпример". Поэтому переменная, созданная с помощью оператора walrus, всегда будет давать нам первого "свидетеля"/"контрпример".

Подводные камни и ограничения

Ранее в тексте я пытался мотивировать вас использовать оператор walrus. Полагаю, важно также предупредить о некоторых недостатках и ограничениях в отношении этого оператора.

В предыдущем примере было показано, что короткая схема может быть полезна для захвата значений в any()/all(), но в некоторых случаях это может привести к неожиданным результатам:

for i in range(1, 100):
    if (two := i % 2 == 0) and (three := i % 3 == 0):
        print(f"{i} is divisible by 6.")
    elif two:
        print(f"{i} is divisible by 2.")
    elif three:
        print(f"{i} is divisible by 3.")

# NameError: name 'three' is not defined

Во фрагменте выше приведено условное выражение с 2 объединенными присваиваниями, проверяющими, на сколько делится число — на 2, 3 или 6 в порядке очередности (если условие 1 верно, то 2 и 3 тоже верно). На первый взгляд это может казаться интересным трюком, но благодаря короткой схеме вычисления, если выражение (two := i % 2 == 0) будет неверным, то следующее условие будет пропущено, а переменные останутся не определены или будут иметь неактуальные значения от предыдущей итерации.

Короткая схема вычисления логического выражения все же может быть выгодной/намеренной. Например, можно ее использовать с регулярными выражениями для поиска соответствия нескольким шаблонам в строке:

import re
tests = ["Something to match", "Second one is present"]

pattern1 = r"^.*(thing).*"
pattern2 = r"^.*(present).*"

for test in tests:
    m = re.match(pattern1, test)
    if m:
        print(f"Matched the 1st pattern: {m.group(1)}")
    else:
        m = re.match(pattern2, test)
        if m:
            print(f"Matched the 2nd pattern: {m.group(1)}")

# Соответствие первому шаблону: thing
# Соответствие второму шаблону: present

for test in tests:
    if m := (re.match(pattern1, test) or re.match(pattern2, test)):
        print(f"Matched: '{m.group(1)}'")
        # Соответствие: 'thing'
        # Соответствие: 'present'

Мы уже рассматривали версию этого фрагмента в разделе «Рассмотрим основы», где использовали if/elif вместе с оператором walrus. Здесь же представлено упрощение через схлопывание условия в один if.

Если вы только познакомились с оператором walrus, то можете заметить, что он заставляет область видимости переменных вести себя иначе в list comprehensions.

values = [3, 5, 2, 6, 12, 7, 15]
tmp = "unmodified"
dummy = [tmp for tmp in values]
print(tmp)  
# Как ожидалось, переменная "tmp" не была переопределена. 
# Она по-прежнему имеет привязку к значению "unmodified"

total = 0
partial_sums = [total := total + v for v in values]
print(total)  # 50

С использованием обычных list/dict/set comprehensions, область видимости переменной цикла остается внутри конструкции и, следовательно, любая существующая переменная с тем же именем останется неизменной. Однако с использованием оператора walrus, переменная из comprehension total остается доступной после вычисления значения конструкции, получая присвоенное значение внутри comprehension.

Когда использование walrus в коде становится более удобным для вас, вы можете попробовать использовать его в других случаях. Но есть один случай, в котором вам не удастся его использовать — выражения с with (менеджером контекста):

class ContextManager:
    def __enter__(self):
        print("Entering the context...")

    def __exit__(self, exc_type, exc_val, exc_tb):
        print("Leaving the context...")

with ContextManager() as context:
    print(context)  # None

with (context := ContextManager()):
    print(context)  # <__main__.ContextManager object at 0x7fb551cdb9d0>

Когда мы используем обычный синтаксис with ContextManager() as context: ..., контекст привязывается к возвращаемому значению context.enter(), тогда же как при использовании версии с := происходит связь с результатом самого ContextManager(). Зачастую это не важно, потому что context.enter() обычно возвращает self, но в случае, если это не так, будет крайне сложно отладить проблему.

Для более практического примера рассмотрим ниже, что происходит при использовании оператора walrus с контекстным менеджером closing:

from contextlib import closing
from urllib.request import urlopen

with closing(urlopen('https://www.python.org')) as page:
    for line in page:
        print(line)  # Выводится вебсайт в формате HTML

with (page := closing(urlopen('https://www.python.org'))):
    for line in page:
        print(line)  # TypeError: 'closing' object is not iterable

Еще одна проблема, с которой вы можете столкнуться — относительный приоритет :=, который ниже, чем другие логические операторы:

text = "Something to match."
flag = True

if match := re.match(r"^.*(thing).*", text) and flag:
    print(match.groups())  # AttributeError: 'bool' object has no attribute 'group'

if (match := re.match(r"^.*(thing).*", text)) and flag:
    print(match.groups())  # ('thing',)

Здесь нам нужно обрамлять выражение присваивания в скобки для обеспечения гарантии, что результат re.match(...) будет записан в переменную. Если мы этого не сделаем, выражение and будет рассчитано в первую очередь и переменной будет присвоен логический результат выражения.

И наконец, есть некоторая ловушка или скорее легкое ограничение. В данный момент нельзя использовать аннотации типов на той же строке с оператором walrus. Следовательно, если вы хотите определить тип переменной, то выражение следует разделить на 2 строки:

from typing import Optional
value: Optional[int] = None
while value := some_func():
    ...  # Описание действия

Заключительные мысли

Как в случае с любой особенностью синтаксиса языка, злоупотребление оператором walrus может привести к ухудшению ясности и читаемости кода. Не следует внедрять его в коде при каждом удобном случае. Воспринимайте этот оператор как инструмент — будьте осведомлены о его преимуществах и недостатках и используйте его там, где это уместно.

Если хотите ознакомиться с большим количеством практических использований оператора walrus, сверьтесь с его представлением в стандартной библиотеке CPython — все изменения могут быть найдены в этом PR.

Кроме того, я также рекомендую прочитать PEP 572: в нем содержится еще больше примеров, а также обоснование внедрения оператора в стандартную библиотеку.

Комментарии (46)


  1. aamonster
    15.09.2022 13:02
    +8

    А short circuit (короткое замыкание) разве переводят как "короткий цикл"?


    1. EvgeniyZemskiy Автор
      15.09.2022 14:18
      +7

      Спасибо. Действительно, термин короткое замыкание является устоявшимся, исправил в статье.


      1. RAX7
        15.09.2022 15:01
        +1

        Это у электриков "короткое замыкание" устоявшийся термин. В данном контексте short circuit всё же переводится как вычисления по короткой схеме


        1. mayorovp
          15.09.2022 15:18
          +5

          Поскольку термин short circuit является метафорой, прямо отсылающей к "электрикам" — то и перевод можно использовать тот же самый.


          А по вышей ссылке наблюдается явная нехватка источников.


          1. trinxery
            15.09.2022 15:23

            "short-circuit evaluation" - "вычисление по короткой цепи" (досл.); не похоже что эта метафора так легко используется прямо и без адаптации. Как "КЗ" превратить в эти самые "вычисления" понять крайне затруднительно.


          1. aamonster
            15.09.2022 19:19

            Я бы посмотрел перевод в документации M$ и подобных гигантов. У них есть гайдлайны для переводов, так что должно быть всегда одинаково. Там не всегда идеально (от перевода чекбокса я до сих пор подёргиваюсь), но велик шанс, что их перевод будет/станет общепринятым.


            1. mayorovp
              15.09.2022 19:56
              +3

              Вот документация от Microsoft — последнее место где надо искать правильный перевод. Они даже не пытаются сделать его правильно.


              1. aamonster
                16.09.2022 07:48

                Дело не в правильности, а в шансах, что они продавят свой перевод и он станет общепринятым.


  1. bret99
    15.09.2022 13:08
    +31

    Опять про моржа...Кому как, но субъективно укорочение кода нередко приводит к его нечитабельности. Вопрос, надо ли приносить операторы из других языков для того, чтобы "стильно, модно, молодежно", с очень сомнительным выигрышем в производительности (он вообще есть..?), остается открытым и делом вкусовщины.


  1. vadimr
    15.09.2022 13:09

    оператор Walrus

    Уж или “моржовый оператор”, или “оператор :=”. Это google translate, что ли?


  1. IvanSTV
    15.09.2022 13:19
    -13

    извините за офтоп, а почему сотрудник компании МойОфис кодит на питоне, а компания в продукт в качестве языка макросов воткнула ублюдочный LUA?


    1. trinxery
      15.09.2022 13:44
      +13

      Как язык, часто применяемый как раз для скриптинга внутри приложений. Чтобы не тащить немаленький питон или любой другой язык, и для своей роли выглядит он вполне неплохо


      1. IvanSTV
        15.09.2022 13:54
        -6

        и что ж там неплохого? То, что делалось в VBA на 5 строчек стало 20?

        Плюс IDE встроенный в мойофис абсолютно ублюдочный. Макрорекордер не только не помогает, но еще больше запутывает. Я понимаю, что у кого-то здесь реклама и я не в кассу со своими претензиями. Но доколе?

        Про питон. Сейчас нет нужды тащить его немаленький весь и целиком. Достаточно обеспечить базовый функционал и дальше подключить кастомные библиотеки, Да и того... у меня на ноуте терабайт. Я себе для табличного анализа и питон поставлю. и все остальное. Табличный анализ - он не делается на печатной машинке. Аргументы про размер так себе.


        1. trinxery
          15.09.2022 14:07
          +9

          Плюс IDE встроенный в мойофис абсолютно ублюдочный

          Если IDE плохая, то она будет такой и с питоном, и с lua

          Сейчас нет нужды тащить его немаленький весь и целиком. Достаточно обеспечить базовый функционал

          И какие же части стандартной библиотеки нам оставить, а какие выпилить? И это будет уже не чистый питон, что создаёт ситуации когда человек пишет на питоне обыкновенном а почему-то код не работает

          Да и того... у меня на ноуте терабайт

          (так и хочется написать "из-за таких как вы у нас калькуляторы на электроне") В конце концов "мойофис" создан в первую очередь для госконтор с госкомпами, которые к печатной машинке обычно ближе, чем к ноуту "с терабайтом"


          1. IvanSTV
            15.09.2022 14:24
            -6

            И какие же части стандартной библиотеки нам оставить, а какие выпилить? И это будет уже не чистый питон, что создаёт ситуации когда человек пишет на питоне обыкновенном а почему-то код не работает

            в VBA именно так относительно VB, и никаких проблем не было

            Если IDE плохая, то она будет такой и с питоном, и с lua

            IDE усиливает ублюдочность Lua

            В конце концов "мойофис" создан в первую очередь для госконтор с госкомпами, которые к печатной машинке обычно ближе, чем к ноуту "с терабайтом"

            В таком случае компании надо определиться, то ли они делают софт для печатных машинок. то ли они делают полноценный офисный продукт. А то везде дуют в уши, что полноценный продукт, а реально продукт неполноценный. Но даже не в этом дело - нет даже понимания собственной ущербности, и, соответственно, не видно желания как-то исправлять.


            1. trinxery
              15.09.2022 14:44
              +6

              в VBA именно так относительно VB, и никаких проблем не было

              Сомневаюсь, что из VB вообще можно было много урезать, а питон мы берём в частности и из-за его обширной стандартной библиотеки

              ублюдочность Lua

              О вкусах не спорят, все дела (но тогда и не стоит во второй раз упоминать "ублюдочность"), но, имхо, Луа нормально выглядит; может быть стоит убрать остатки паскаля в виде begin/end, но проще уж оставить стандартный Луа

              В таком случае компании надо определиться, то ли они делают софт для
              печатных машинок. то ли они делают полноценный офисный продукт. А то
              везде дуют в уши, что полноценный продукт, а реально продукт
              неполноценный.

              Когда-то мне приходилось сидеть за нетбуком с двумя гигами рамы. Линукс работает нормально, винда - нет. Firefox работает неплохо, хром - нет. Все четверо - полноценные продукты, но некоторые работают на "печатной машинке", некоторые нет

              Но даже не в этом дело - нет даже понимания собственной ущербности, и, соответственно, не видно желания как-то исправлять.

              Пользовались "Мойофисом"? Я - нет, но я как-то и не слышал заявлений прямо об "ущербности" продукта. Да, недоработки есть, функционал неполный, но всё же, или вывод сделан только по причине использования Lua?


              1. IvanSTV
                15.09.2022 16:32

                а питон мы берём в частности и из-за его обширной стандартной библиотеки

                по размеру стандартная библиотека не больше стандартной для VBA. И десятки лет те же госконторы пользовались и претензий о размерах не высказывали. В мелкософтах сейчас в принципе размеры такие, что туда-сюда гигабайт-не велика проблема. И всегда так было, соразмерно масштабам. Выбор именно этого языка - это попытка подмять разработку пользовательских приложений под себя или просто продекларировать, наличие при фактическом отсутствии?

                Lua не позволяет полноценно автоматизировать и закрывать отсутствующие функции. Повторяю, язык, в отличие от VBA не развит, объектная база скудная, стандартные библиотеки скудные. Прочитал инструкцию по Lua и охренел, потому что простое изменение шрифта в выделении превращается в квест.

                Все четверо - полноценные продукты, но некоторые работают на "печатной машинке", некоторые нет

                МойОфис не сильно экономит память и ресурсы, да. поменьше мелкософтов, но функционал тоже пропорционально меньше. Про полноценность я бы не говорил, потому что стандартных инструментов мало, и поддержки макросов фактически тоже нет: язык и IDE к пользователю недружелюбны по максимуму, а некоторые вещи вообще нереализуемы (по крайней мере, из того, что я прочитал). Какая мне разница, если я сильно теряю в функционале, переходя на него?

                Пользовались "Мойофисом"? Я - нет, но я как-то и не слышал заявлений прямо об "ущербности" продукта.

                перед глазами, ради тестирования. Как бы нехилый вызов - переписать всю свою кучу примочек и костылей с VBA на Lua при том. что инструмент не позволяет толком обратиться с ячейке без реверансов.


                1. trinxery
                  15.09.2022 16:53
                  +3

                  по размеру стандартная библиотека не больше стандартной для VBA

                  я не спец в VBA, вы не спец в питоне, но я слышал как о с.б. питона отзываются как о [чуть ли не] мощнейшей среди всех языков вообще.

                  И десятки лет те же госконторы пользовались и претензий о размерах не высказывали. В мелкософтах сейчас в принципе размеры такие, что туда-сюда гигабайт-не велика проблема.

                  в условном "офисе 2007", да, размеры будут поменьше (предвещая ответ: да, точно есть места с относительно новым пакетом софта, но мест с софтом старым гораздо больше)

                  просто продекларировать, наличие при фактическом отсутствии

                  то есть для вас ни один встраиваемый язык кроме VBA за язык и не считается?

                  Lua не позволяет полноценно автоматизировать и закрывать отсутствующие функции. Повторяю, язык, в отличие от VBA не развит, объектная база скудная, стандартные библиотеки скудные.

                  Потому что это встраиваемый язык. Окружение должно предоставлятся программой

                  Прочитал инструкцию по Lua и охренел, потому что простое изменение шрифта в выделении превращается в квест.

                  Вопросы к авторам софта, не к Луа. И VBA можно в такое превратить, только майкрософт предоставили нормальное окружение, в отличие от авторов мойофиса. Условный доступ к ячейке или что угодно ещё для взаимодействия с продуктом - зона ответственности не Луа, а разработчиков этого самого продукта.

                  Про полноценность я бы не говорил, потому что стандартных инструментов мало, и поддержки макросов фактически тоже нет: язык и IDE к пользователю недружелюбны по максимуму, а некоторые вещи вообще нереализуемы (по крайней мере, из того, что я прочитал). Какая мне разница, если я сильно теряю в функционале, переходя на него?

                  Опять история про окружение и суть встраиваемых языков. Такие языки должны предоставлять основные функции и возможности собственного расширения.

                  Как бы нехилый вызов - переписать всю свою кучу примочек и костылей с VBA на Lua

                  С Lua на VBA не лучше

                  при том. что инструмент не позволяет толком обратиться с ячейке без реверансов.

                  см. пункты про "окружение"


                  1. IvanSTV
                    15.09.2022 17:32

                    я не спец в VBA, вы не спец в питоне, но я слышал как о с.б. питона отзываются как о [чуть ли не] мощнейшей среди всех языков вообще.

                    у меня и то, и то на ноуте. По размерам ничего страшного. если бы вместо Lua взяли питон, например. Апелляция к размеру несостоятельна.

                    в условном "офисе 2007", да, размеры будут поменьше (предвещая ответ: да, точно есть места с относительно новым пакетом софта, но мест с софтом старым гораздо больше)

                    там, где требуется серьезный анализ данных, соотношение обратное. Да и откуда статистика-то? 2007 активно заменялся - прошло 15 лет. Я его даже когда фрилансил на VBA не видел ни разу.

                    Вопросы к авторам софта, не к Луа. 

                    зона ответственности не Луа, а разработчиков этого самого продукта.

                    вот я и задаю вопросы к авторам софта в первую очередь. Авторам Луа во вторую, потому что в дополнение и сам язык недружелюбен к юзеру - много излишнего синтаксиса, нет многих методов, которые в других языках есть, например. Но главный вопрос ко всем - какого хера?

                    Lua специфичен как внутренний язык для тех программ. где требуется КВАЛИФИЦИРОВАННАЯ ДОРАБОТКА ПОД ПОЛЬЗОВАТЕЛЯ. А в качестве языка массового пользования с низким порогом он абсолютно непригоден - все, вываливающееся за пределы куцего набора встроенных функций и операторов, выполняется через C API. Есть разница между - у меня замначальника склада с помощью макрорекордера, гугла и какой-то матери в экселе накропал форму для проверки инвентаризаций и я судорожно ищу, где бы мне нанять фрилансера, чтобы накропал на склад форму для проверки инвентаризаций, потому что мне некогда, а мужик никогда не разберется с этой хренью, особенно с API даже если его накачать амфетаминами для повышения работоспособности. Это безотносительно окружения

                    Опять история про окружение и суть встраиваемых языков. 

                    Нет, не только. И выбор Lua неудачен - таргет-группа его не примет - и реализация еще более ухудшает этот выбор.

                    С Lua на VBA не лучше

                    лучше и проще. Я с джаваскрипта как-то на VBA переписывал код. Никаких особых проблем не встретил, даже улучшил.

                    Резюмирую - сначала вы взялись защищать продукт весь и целиком, теперь у вас все-таки плохие бояре хороший продукт испортили, но царь все равно безгрешен.


                    1. trinxery
                      15.09.2022 17:56
                      +2

                      По размерам ничего страшного. если бы вместо Lua взяли питон, например.

                      мы не берём питон не только потому что он большой, а в том числе и из-за того, что из него многое придётся вырезать, и получится новый ЯП, вместо "везде-одинакого" стандартизированного питона

                      см. также вашу фразу: "Про питон. Сейчас нет нужды тащить его немаленький весь и целиком. Достаточно обеспечить базовый функционал и дальше подключить кастомные библиотеки "

                      вот я и задаю вопросы к авторам софта в первую очередь.

                      (дальше в этой паре абзацев, кстати, претензии опять к софту, а у нас спор про Python/Lua/VBA в разных комбинациях)

                      все, вываливающееся за пределы куцего набора встроенных функций и операторов, выполняется через C API

                      стало даже интересно, что такого не могут разработчики софта предоставить через стандартные функции Луа, что нужно аж тащить пробросы в C

                      лучше и проще. Я с джаваскрипта как-то на VBA переписывал код. Никаких особых проблем не встретил, даже улучшил.

                      если изначально написано плохо (в разной степени) то можно хоть на C переписывать и будет лучше

                      сначала вы взялись защищать продукт весь и целиком, теперь у вас все-таки плохие бояре хороший продукт испортили, но царь все равно безгрешен.

                      Спор начался с вашего утверждения что Луа - "ублюдочен" [по сравнению с VBA]. Ваши аргументы про ужасы написания программ для мойофиса не относятся к Луа, повторюсь, был бы VBA в мойофисе при такой же плохой реализации API самого офиса, было бы так же плохо.


        1. ulitin
          16.09.2022 18:09

          Иван, добрый день, я веду направление исследований и UX, мне и моим коллегам из дизайн команды МойОфис было бы очень интересно поговорить про ваш опыт работы с макросами. Просто напишите мне в телеграм ulitin_kirill и запланируем звонок. Спасибо за неравнодушие!


      1. Areso
        15.09.2022 14:41

        есть куча питоноподобных аналогов. Тащить весь Питон не обязательно.


        1. trinxery
          15.09.2022 14:46
          +6

          А есть Луа, как раз созданная для применения в данной сфере; создавать новый язык "не обязательно".


          1. IvanSTV
            15.09.2022 17:01
            -2

            к какой он сфере, кроме садомазохизма применим?

            "Lua не имеет встроенных отладочных средств. Взамен, он предлагает специальный интерфейс функций и перехватчиков (hook). Этот интерфейс позволяет строить различные типы отладчиков, профилировщиков и других инструментов, нуждающихся во "внутренней информации" интерпретатора. "

            Это предлагается пользователю офисных приложений? Насколько далеки же были они от народа, что понесли это в массы!


            1. trinxery
              15.09.2022 17:08
              +2

              А это "обычному пользователю" и не нужно. Ему нужно кататься по полям и строить циклы (или что там у вас); Уверен и VBA можно отлаживать с помощью паяльника, а "пользователь" такое вряд ли сможет применить даже чисто технически где-то в каких-то "моих офисах"


              1. IvanSTV
                15.09.2022 17:40

                А это "обычному пользователю" и не нужно. Ему нужно кататься по полям и строить циклы (или что там у вас);

                э-э-э... то есть, вы предлагаете вмето банального пошагового исполнения с промптом (как это реализовано в VBA) тестировать цикл через костыли специальных тестов? Как у меня один мужик писал макросы. Посмотрит в интернет, скопирует, ни хрена не понимая. Скопировал - смотрит, что получается на каждом шаге. Ошибка - меняет, параметры. Некорректные данные - меняет. Так и шел методом тыка. А в мойофис предлагается сразу начистовую писать загаженную лишним синтаксисом длинную строку строку и молиться, чтобы исполнилось. Вы сильно далеки от реальных требований пользователя малой автоматизации.


                1. trinxery
                  15.09.2022 17:58
                  +1

                  В сотый раз повторю, проблемы API и реализации мойофиса к Луа не относятся. Спор был про качество Луа как встраиваемого языка, дальше см. последний пункт этого моего комментария.


        1. Tresimeno
          16.09.2022 13:21

          Вопрос в том, зачем было тащить туда хоть что, отличное от VBA. В существующих офисных файлах скрипт - это VBA, зачем надо было выделываться и городить свой велосипед? Мотивации так делать я в упор не понимаю.


          1. Areso
            16.09.2022 14:37

            Как бы потому что VBA принадлежит Майкрософту и он не будет счастлив, если кто-то сделает ABV, который будет похож на оригинал до степени смешения.


    1. Akon32
      15.09.2022 15:58
      +2

      Потому что lua подключить проще (сам подключал, тоже некоторые пользователи плюются).

      И вообще, ценность python как встраиваемого языка преувеличена. Он распространён (его знает уйма закончивших курсы людей), много библиотек; и на этом всё. А в остальном lua не хуже как встраиваемый язык.


  1. randomsimplenumber
    15.09.2022 13:19
    +12

    Экономия 1 строчки кода с одной стороны, ухудшение читабельности с другой стороны. имхо, оно того не стоит.


  1. Rsa97
    15.09.2022 13:22
    +6

    это функциональность, которая появилась в Python недавно, в версии 3.8
    Питону 3.8 уже три года, а актуальная версия 3.10.


  1. omichkun
    15.09.2022 13:34
    +12

    Вы б хотя бы смотрели Хабр на предмет наличия таких же статей

    https://habr.com/ru/company/skillfactory/blog/683418/


    1. Habetdin
      15.09.2022 15:28
      +8

      Причём в обеих статьях ссылки на источник совпадают вплоть до символа. @Boomburum, есть ли в планах детектор таких клонов? :)


  1. NeoCode
    15.09.2022 13:59
    +13

    Я уже к прошлой статье такой комментарий писал:) Разработчикам языка следовало бы использовать := для ОБЪЯВЛЕНИЯ переменных, а = для присваивания УЖЕ СУЩЕСТВУЮЩИМ переменным (как в Go). Такой подход значительно обезопасил бы код от опечаток в именах переменных (когда вместо присваивания существующей переменной происходит создание новой).

    А сейчас получается нечто странное:

    x1 = 1        # ok
    x2 := 2       # error
    x3 = (y3 := 3) # ok
    x4 = (y4 = 4)  # error

    Т.е. один оператор работает только вне скобок, другой только в скобках. Причем возможно и вот такое

    c = (d:=1)*(d:=2)

    Какой в этом смысл? Не проще ли было просто разрешить обычный оператор = внутри выражений?


    1. igrishaev
      15.09.2022 16:12
      +2

      для присваивания УЖЕ СУЩЕСТВУЮЩИМ

      В питоне нельзя толком проверить, существует переменная или нет. В любой момент ее можно подсунуть через globals.


      1. NeoCode
        15.09.2022 20:52

        Почему? Я заранее предупреждаю что не знаком с Питоном, но в любом интерпретируемом языке переменные обычно хранятся в некоем словаре, где ключ - имя переменной.

        Соответственно, нет ничего проще: операция "=" могла бы проверять наличие имени в словаре, и если имени нет - ошибка, если есть - обращение к значению. Операция ":=" аналогично могла бы проверять наличие имени в словаре, но ошибка генерируется если такое имя есть. Если имени нет, то добавлять в словарь имя и значение.

        Как именно то или иное имя попало в словарь - совершенно неважно.


        1. onegreyonewhite
          16.09.2022 02:44

          Получилась бы сомнительная польза в ущерб производительности. Словарь в Python'е одна из самых проблемных и медленных сущностей, но на ней держится вся логика переменных. Каждая такая проверка замедлила бы код минимум процентов на 20-30%.

          Единственный вариант, как я вижу, если и делать такую проверку, то с помощью mypy. Но кмк это просто никому не нужно, поэтому никто и не делает. Да и, опять же, кмк это только усложнило бы читабельность.


          1. NeoCode
            16.09.2022 08:52

            Словарь это просто ассоциативный массив. Структура данных, основанная на хеш-таблице, дереве того или иного вида или на чем-то еще. Такая проверка уже делается в любом случае при каждом обращении к словарю, естественным путем, она уже существует в коде реализации словаря, потому что словарю нужно в какой-то момент принимать решение - создавать новый элемент или нет. Это решение принимается уже сейчас при каждом обращении к каждой переменной. Т.е. по скорости ничего не изменится.


            1. onegreyonewhite
              16.09.2022 13:14

              Вы предлагаете дважды делать эту проверку или реализовать функционал, при котором в словаре можно будет бросать исключение при наличии ключа?

              В любом случае это нафиг никому не нужно, поэтому никто не хочет усложнять код и синтаксис. Единственное, где это могло бы пригодиться - mypy. Но и тут это не нужно никому видимо.


  1. serafims
    15.09.2022 16:13
    +7

    При Никлаусе Вирте такого не было!..


    1. masai
      16.09.2022 00:52
      +1

      Кстати, := — это не изобретение Вирта. Это ещё в ALGOL было, по образу которого во многом и создавался Pascal. Впрочем, в ALGOL много чего было. Например, сопрограммы.


  1. Revertis
    15.09.2022 17:40
    +8

    Вы можете сказать "Просто добавь y = func(x) перед объявлением списка и тебе не понадобится оператор walrus!". Можно так сделать, но для этого потребуется еще одна дополнительная строка кода и, на первый взгляд, без знания о том, что func(x) очень медленная, может быть неясно, зачем эта переменная нужна.

    Решил разрезать на две части:

    но для этого потребуется еще одна дополнительная строка кода

    А что в этом плохого? У вас буквы платные? Читабельность это главное! Не надо делать так, как в первом примере!

    и, на первый взгляд, без знания о том, что func(x) очень медленная, может быть неясно, зачем эта переменная нужна

    Как зачем??? Чтобы не вызывать 3 раза одну и ту же функцию! Это любой начинающий прогер сам догадается. Вызовы ведь вообще не бесплатные!


    1. Groosha
      16.09.2022 12:50

      Так-то в Python есть ещё и кэши самых разных сортов. Закэшируй func(x) и вычислится она ровно один раз. Профит! (это как дополнение к комментарию)


      1. Revertis
        16.09.2022 13:16
        -1

        Ваши специальные кэши никому не нужны. Самый оптимальный кэш - y = func(x) .


  1. NNikolay
    15.09.2022 18:42

    Мне нравятся некоторые примеры. С f-стринг, например. Но первый пункт не очень. Если там такая медленная функция, то проще с этим бороться в самой функции на не в местах её использования. Взять декоратор кеширования из functools, например.