Что нового ожидается в Python 3.9

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

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

    Оператор объединения словарей (PEP-584)
    До этих пор, объединить словари можно было несколькими способами, однако каждый из них имел небольшие недостатки или нюансы.
    Несколько способов объединения словарей
    1. Использовать метод update словаря
    d1 = {'one': 1}
    d2 = {'two': 2}
    # Приходится либо обновлять уже существующий,..
    d1.update(d2)
    # ...либо создавать копию. 
    united_dict = d1.copy()
    united_dict.update(d2)
    

    2. Распаковка двух словарей в один
    united_dict = {**d1, **d2}
    

    Про это даже Гвидо говорит, что это выглядит не очень, да и надо еще догадаться или вспомнить про такую опцию, но многих устроило бы.
    3. Еще вариант похожий на предыдущий dict(d1, **d2), о котором тоже не сразу можно догадаться.Да к тому же не будет работать, если в d2 присутствую не строковые ключи.
    4. collections.ChainMap
    Еще один неочевидный способ.
    Мне кажется странным импортировать даже из стандартной библиотеки, для такого рядового действия, как объединение двух словарей.
    from collections import ChainMap
    d1 = {'one': 1}
    d2 = {'two': 2}
    united_dict = ChainMap(d1, d2)
    

    При этом, если вы захотите изменить элемент в объединенном словаре, то изменится и элемент в изначальном словаре, о чем очень критично помнить. Мне сложно представить, что для кого-то подобная фича окажется полезной.

    Теперь можно писать просто
    united_dict = d1 | d2
    # или, для того чтобы добавить элементы одного словаря другому, что аналогично методу update():
    d1 |= d2
    

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

    Упрощение аннотаций для контейнеров и других типов, которые могут быть параметризованы (PEP-0585)
    Следующее нововведение очень пригодится тем, кто пользуется аннотацией типов.
    Теперь упрощается аннотация коллекций, таких как list и dict, и вообще параметризованных типов.

    Для таких типов вводится термин Generic — это тип который может быть параметризован, обычно контейнер. Например, dict. И вопрос в том, как следует корректно переводить его, так чтобы не ломило зубы. Очень уж не хочется пользоваться словом «дженерик». Так что в комментариях очень жду другие предложения. Может где-то в переводах встречалось получше название?
    Параметризованный generic: dict[str, int].

    Так вот для таких типов теперь не надо импортировать соответствующие аннотации из typing, а можно использовать просто названия типов.
    Например
    # вместо
    from typing import List
    List[str]
    # теперь
    list[int]
    

    Что конечно намного удобнее и понятнее.

    Другой пример:
    # раньше
    from typing import OrderedDict
    OrderedDict[str, int]
    # теперь
    from collections import OrderedDict
    OrderedDict[str, int]
    

    Полный список типов
    tuple # typing.Tuple
    list # typing.List
    dict # typing.Dict
    set # typing.Set
    frozenset # typing.FrozenSet
    type # typing.Type
    collections.deque
    collections.defaultdict
    collections.OrderedDict
    collections.Counter
    collections.ChainMap
    collections.abc.Awaitable
    collections.abc.Coroutine
    collections.abc.AsyncIterable
    collections.abc.AsyncIterator
    collections.abc.AsyncGenerator
    collections.abc.Iterable
    collections.abc.Iterator
    collections.abc.Generator
    collections.abc.Reversible
    collections.abc.Container
    collections.abc.Collection
    collections.abc.Callable
    collections.abc.Set # typing.AbstractSet
    collections.abc.MutableSet
    collections.abc.Mapping
    collections.abc.MutableMapping
    collections.abc.Sequence
    collections.abc.MutableSequence
    collections.abc.ByteString
    collections.abc.MappingView
    collections.abc.KeysView
    collections.abc.ItemsView
    collections.abc.ValuesView
    contextlib.AbstractContextManager # typing.ContextManager
    contextlib.AbstractAsyncContextManager # typing.AsyncContextManager
    re.Pattern # typing.Pattern, typing.re.Pattern
    re.Match # typing.Match, typing.re.Match


    Для строк появились методы removeprefix() и removesuffix() (PEP 616)
    Здесь всё просто. Если строка начинается с префикса, то вернется строка без этого префикса. Если префикс повторяется несколько раз, то он удалится только один раз. Аналогично с суффиксом:
    some_str = 'prefix of some string and here suffix'
    some_str.removeprefix('prefix')
    >> ' of some string and here suffix'
    some_str.removesuffix('suffix')
    >> 'prefix of some string and here '
    

    Текущие альтернативы
    1. Проверять, если строка начинается с префикса, то вычитать из строки количество букв префикса — именно так будет работать новый метод removeprefix.
    def removeprefix(self: str, prefix: str, /) -> str:
        if self.startswith(prefix):
            return self[len(prefix):]
        else:
            return self[:]
    

    2. Использовать lstrip, rstrip:
    	'foobar'.lstrip(('foo',))
    

    Но есть риск удалить больше чем нужно в случае, когда строка начинается с повторения префикса, а надо удалить только один.

    Несколько изменений в модуле math
    Функция math.gcd() нахождения наибольшего общего делителя теперь принимает список целых чисел, так что можно находить одной функцией общий делитель больше, чем для двух чисел.
    Появилась функция для определения наименьшего общего кратного math.lcm(), которая так же принимает неограниченное количество целых чисел.
    Следующие две функции взаимосвязаны.
    math.nextafter(x, y) — вычисляет ближайшее к x число с плавающей точкой, если двигаться в направлении y.
    math.ulp(x) — расшифровывается как «Unit in the Last Place» и зависит от точности расчетов вашего компьютера. Для положительных чисел вернется наименьшее значение числа, такое что при его прибавлении x + ulp(x) получится ближайшее число с плавающей точкой.
    import math
    
    math.gcd(24, 36)
    >> 12
    math.lcm(12, 18)
    >> 36
    math.nextafter(3, -1)
    >> 2.9999999999999996
    3 - math.ulp(3)
    >> 2.9999999999999996
    math.nextafter(3, -1) + math.ulp(3)
    >> 3.0 
    

    Теперь любое валидное выражение может быть декоратором (PEP-0614)
    С декораторов снимается ограничение, по которому декоратором может выступать только имя и его синтаксис допускал только разделение точками.

    Не думаю, что многие задумывались о существовании такого ограничения, но в описании pep приведен пример, когда нововведение делает код стройнее. По аналогии, можно привести такой
    упрощенный и искусственный пример:
    def a(func):
    	def wrapper():
    		print('a')
    		func()
    	return wrapper
    	
    def b(func):
    	def wrapper():
    		print('b')
    		func()
    	return wrapper
    	
    decorators = [a, b]
    
    @decorators[0] # в версии 3.8 и ранее интерпретатор споткнулся бы на этих скобках
    def some_func():
    	print('original')
    	
    some_func()
    >> a
    >> original
    

    В модуль ast добавили метод unparse (bpo-38870)
    Как понятно из названия он может по ast.AST объекту скомпилировать исходную строку. Однажды, мне даже хотелось таким воспользоваться и было удивительно, что такого метода нет.
    Пример:
    import ast
    parsed = ast.parse('import pprint; pprint.pprint({"one":1, "two":2})')
    unparsed_str = ast.unparse(parsed)
    print(unparsed_str)
    >> import pprint
    >> pprint.pprint({'one': 1, 'two': 2})
    exec(unparsed_str)
    >> {'one': 1, 'two': 2}
    

    Новый класс functools.TopologicalSorter для топологической сортировки направленных ациклических графов (bpo-17005)
    Граф который передается в сортировщик, должен быть словарем, в котором ключи выступают вершинами графа, а значением является итерируемый объект с предшественниками (вершинами, дуги которых указывают на ключ). В качестве ключа, как обычно, подойдет любой хешируемый тип.
    Пример:
    Возьмем к примеру граф из статьи википедии:

    from functools import TopologicalSorter
    graph = graph = {8: [3, 7], 11: [5, 7], 2: [11], 9: [8, 11], 10: [3, 11]}
    t_sorter = TopologicalSorter(graph)
    t_sorted_list = list(t_sorted_list.static_order()) # в случае, когда распараллеливания не требуется, можно использовать напрямую метод static_order.
    >> [3, 7, 5, 8, 11, 2, 9, 10]
    


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

    В http.HTTPStatus добавлены новые статусы, которые мы так долго ждали:
    103 EARLY_HINTS
    418 IM_A_TEAPOT
    425 TOO_EARLY

    И еще несколько изменений:
    • Ускорены встроенные типы (range, tuple, set, frozenset, list) (PEP-590)
    • "".replace("", s, n) теперь возвращает s, а не пустую строку, для всех ненулевых n. Это выполняется и для bytes и bytearray.
    • ipaddress теперь поддерживает парсинг адресов IPv6 с назначениями.

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

    Более подробно можно почитать:
    docs.python.org/3.9/whatsnew/3.9.html
    www.python.org/downloads/release/python-390a6
    В общем, не сказать, что грядущие изменения — это то чего все давно ждали и без чего невозможно обойтись, хотя есть некоторые приятные моменты. А что вам показалось наиболее интересным в новой версии?

    UPD:
    обновлена ссылка на последний релиз
    добавлен PEP-0585 про аннотацию типов

    Similar posts

    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 46

      0
      Пардон, музыка навеяла: вчера вышел 3.8.3
        +2
        Почему TopologicalSorter лежит в functools? Что тут функционального?

        Что происходит в выпиливанием GIL? Это самое важное, что ожидалось в 3.8, но было перенесено на следующий релиз.
          0
          Хорошие вопросы.
          В bugs.python.org/issue17005 единственное побуждение положить в functool аргументировано, что топологическая сортировка «is somewhat related to total ordering», но большого обсуждения куда бы лучше положить этот класс судя по всему не было.
          Про GIL, если речь про www.python.org/dev/peps/pep-0554, то похоже он перенесен на 3.10 или позднее
            +6
            Что происходит в выпиливанием GIL?

            Да, для меня до сих пор самое большой разочарование в Питоне — картонная многопоточность.
            Для I/O всякого подходит, для вычислений — извините, плодите процессы и пиклите данные тудя сюда.


            Позор для современного языка… при этом не использовать его вариантов часто нет — тонны библиотек, особенно в сфере работы с данными — только на нём.

              0
              пиклите данные тудя сюда
              Так уже в 3.8 завезли shared memory…
                0

                Не отследил, спасибо.


                Но мне часто приходится писать для систем вроде RH/CentOS7 где Python 3.6 — предел мечтаний. Можно, конечно, собрать последний и забандлить его в venv, но иногда это не подходит по организационным причинам.


                В любом случае — надо изучить насколько оно удобно.

                  0
                  даже в centos8 был 3.6. Поэтому мы просто собрали 3.7 пакетами и положили в локальную репу…
                  +1
                  Который обертка вокруг mmap, существующего с Python 2.x
                +4
                GIL — зло. Но с ним, языком может пользоваться любой человек с общими знаниями о программировании (или даже без них). Вокруг меня туча народу струячит код на питоне, и я не уверен, что многие из них готовы к гонкам состояний, а многопоточность они хотят прямо сейчас.

                Имхо пусть python остаётся гибким и выразительным языком. А многопоточный счёт лучше делать на golang, там для этого всё есть. Ну а если очень хочется многопоточности — есть асинхронность, что поможет в большинстве задач, типа web-бекенд, либо использовать многопроцессность, где для отстрела себе конечностей нужно приложить специальные усилия…
                  +2

                  Гонки-то и с GIL тоже возможны. GIL позволяет разве что не сломать внутреннее состояние интерпретатора, а записать переменную невовремя из другого потока всё равно никто не мешает (как раз три дня назад дебажил одну гонку)

                    0
                    Но сильно меньше, не так ли?
                      +1

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

                    +4
                    Последнюю почти декаду многопроцессорность и многопоточность развивались не особо активно. То есть вроде они и есть, но 99% программ и программистов — просто это не используют. Наилучший показатель, что еще год назад 4х ядерные (часто 4х поточные) интелы покрывали все задачи пользователей. Большинство использовали однопоточность с костылями, чтобы работать немного быстрее на нескольких ядрах.

                    АМД разворошила этот улий. Когда ядер 16 и больше, уже никакие костыли не работает. То что майкрософт в прошлом году активно оптимизировала ядро под новое количество потоков — хороший показатель. Даже такие гиганты зашевелились.

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

                    Нужно ли делать условный питон 4 для многопоточности? Мое мнение — нужно. Сможет ли общество питона пережить новый мажорный релиз, когда флеймы 2/3 не утихли? Не сможет.

                    Если питон затянет выпиливания GIL еще на пару лет — возможно мы увидим как питон первалит пик популярности и начнется спад.
                      +5
                      Популярность этого языка в выразительности, универсальности и замечательной способности поддаваться различным изменениям. Мало языков могут быть так неузнаваемо изменены инструментарием не выходящим за пределы стандартной библиотеки. Python — идеальный язык связки различных модулей. Это язык диспетчер. Его задача, в моём идеальном мире, выставить режимы и вызвать скомпилированный на C, C++ или что-нибудь типа golang код, после чего преобразовать результаты в необходимый вид и провести постобработку. Язык который можно расположить посредине между достаточно непростым кодом на вышеупомянутых языках и shell-скриптами (условно, но вот не знаю в ОС где нет shell чего-нибудь адекватного этому). Это язык на котором нужно писать, когда логика, реализованная на shell, уже взрывает мозг или выглядит страшно, но ещё нет таких требований к скорости счёта, чтобы писать на С и подобных. Это явно покрывает больше половины прикладных задач обычных людей. Данная ниша позволит держать язык выразительным и не набивать его костылями. Язык нужно оптимизировать, увеличивать скорость написанных на нём приложений, но нельзя пытаться ворваться в чужую нишу, можно застрять посередине и быть одинаково бесполезным в обеих.

                      Мне вообще кажется, что попытки построить универсальный язык на все случаи жизни породило море уродов и нанесло в мир ИТ слишком много энтропии… Но это моё мнение.
                        +1
                        Я согласен с выразительностью. НО!

                        1) Язык уже несколько лет пичкают костылями. Я уже не знаю вещей, которые в питоне можно сделать 1 спсобом, а не несколькими. А это прямое противаречие зен. То есть в моих глазах питон — уже «урод». Хотя все еще лучше большинства.

                        2) Котлин и раст могут быть очень сильно изменены. Котлин так вообще рекламируется что на нем можно писать DSL прямо из языка. Я даже ловил минусы когда обсуждаел эту тему в посте ителж идеи.

                        Раст вообще сделан именно для этой задачи — возможность на ASM.js использовать/создать любой язык.

                        Из того что я вижу, условная половина языков новой волны — выполняют это требование.

                        3) Питон стоит у истоков всех трендов где многопоточность нужна. ИИ, биг дата, моделирование, микросервисы, скриптинг. Окей, все кроме игр. Мне сложно предствавить сколько костылей там вставленно для каждой задачи на уровне кровавого ентерпрайза. Именно эти тренды делают питон одним из самых (имхо — самым) распростаненных языков. И количество костылей там только растет. Это только вопрос времени, когда в каждой из областей свичнутся, если питон не начнет решать свои проблемы.

                        Потому что я не вижу как общество питона ценит эти области. У каждой области есть свои либы. И эти либы активно дрейфуют от языка. Они уже патчат ядро спитона. Дальше только форк на отдельный язык. Но потому что общество не ценит тренды — сам язык тоже от них дрейфует.

                        4) CPython как проект на С — очень плохого качества. И технический долг там уже сильно мешает внедрять новые полезные вещи. Кстати, это причина которая привела к тому, что гугл остался на 2 и будет ее сам патчить.

                        Получается смешно. Чтобы починить причину конфликта питон2/3 надо создать новый конфликт — питон3/4.
                          0
                          Кстати, это причина которая привела к тому, что гугл остался на 2 и будет ее сам патчить.


                          А где можно об этом почитать? Вроде гугл задеприкейтил python2 и всеми силами мигрирует на python3.
                            0
                            не смог найти именно той новости, что я читал.
                            Но все облачные провайдеры говорят, что будут поддерживать (амазон, гугл, редхат)
                            cloud.google.com/python/docs/python2-sunset
                              0
                              Это больше следствие инерции внедрения, чем принципиальных проблем нового языка или кода реализации.

                              Хотя есть факторы и в пользу старого языка. У меня есть большой проект сетевого общения (не HTTP), так там переход на Py3 замедлил скорость процентов на 10 из-за того, что после первичного парсинга байтового прихода с сети — идёт конверсия в строки и уже дальше работа с str (которая в нём unicode). Конечно, ускорение процессоров снивелирует эту регрессию, но всё равно как-то не очень хорошо…
                                +1

                                Но ведь ничто не мешает продолжать работать с байтами без юникода, не? Почти всё, что можно делать с юникодными строками, можно делать и с байтами

                            0
                            Я не совсем понимаю 3 пункт. Биг дата, ии, моделирование и прочие задачи написаны на си, плюсах, фортране и имеют обертку в виде питона. Они уже используют многопоточность, каким образом «реальная» многопоточность в питоне сможет помочь в этих задачах? Перепишут ли математические библиотеки с си на питон? — нет. Станет ли кто-то использовать го для интерактивной работы с датафреймами вместо питона? — очень сильно сомневаюсь. Сможет ли многопоточный питон противостоять го в микросервисном мире, где нужна условно высокая производительность — нет, да и зачем? Останется ли питон в вебе — да, просто потому, что писать «не хайлоад» на джанге просто приятней чем на го.
                              0
                              Многие вещи начинались в университетах на чистом питоне. Потому они взрослели и их ускоряли вставками си или обертками старых решений. И сейчас действительно сложно сказать, что это были питон проекты. Но они ими были. И в этом проблема.

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

                              PyPy, с другой стороны, как раз пытается идти на встречу таким проектам.
                            0
                            Думаете, что в ближайшие годы такому «клею» можно обойтись без удобной многопоточности? Вот не думаю честно, что это так.
                              0
                              Сейчас го — очень активно занимает нишу «клея». Хочу заметить что MVP и бизнес логика — другая ниша. А скриптинг — третья.

                              И да, в клее без многопоточности никак.

                              В скриптинге питон все еще король.
                            0
                            Обо всем этом Герб Саттер писал еще в 2005 году. Более того, программисты, ученые и исследователи тоже не сидели на месте все эти годы — языки программирования, библиотеки, подходы и паттерны программирования получили огромное развитие. Все эти средства, при должном использовании, помогают сильно облегчить разработку и уменьшить количество ошибок в коде.

                            Сейчас есть некоторый хайп вокруг Julia. Кто знает, может это и будет новым «питоном 4 для многопоточности».
                              0
                              Да я читал. Но на практике мы очень долго сидели на 4 потоках. И костыли работали. Когда количество потоков перевалило за 12 в массовом рынке (или когда стали всем доступны 16) выяснилось что большинство софта было написано под «несколько поточность» а не «труъ многопоточность». Все начали обновлять софт. Из професионального софта только продукты адобе все еще не умеют в многопоточность.

                              Теперь когда 8 потоков будет в каждом ноутбуке — правила сильно меняются.
                            0
                            А многопоточный счёт лучше делать на golang, там для этого всё есть.

                            Да я бы рад, но вот мне допустим нужно немного ML сделать, искать аномалии в Timeseries данных. Для этого мне надо обучить моделек и гонять forecast по новым данным. А это сильно CPU-bound задача.


                            В Go полторы библиотеки для этого и те, скорее всего, заброшены. В Питоне — дофигищи. Поэтому пришлось брать его и костылять там всё это в подпроцессах через (де)сериализацию туда-сюда. Потому что за 30 лет питонцы не осилили мультитрединг, не говоря уже о (ко/го)рутинах...


                            Так что, на мой взгляд, язык определяется его экосистемой — библиотеками и (упаси боже) фреймворками.

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

                              Как обычно, как речь о питоне, так каждый встречный — программист. Будто на других языках "hello world" невозможно осилить...

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

                                1. GIL никак не мешает сделать гонки при некорректной работе, начиная с манипуляцией общими данными за пределами мьютекса. Они реже и менее проблемны, да — segfault не поймаете — но это заслуга языка с AMM, а не GIL.

                                2. На сейчас планы по выпиливанию GIL состоят в том, что в пределах одного процесса можно создать подпроцесс со своим пучком тредов и взаимодействовать с ним точно так же, как сейчас модуль multiprocessing делает это для отдельных процессов. Поэтому такая реализация ничего вам не сломает — просто для 99% кода можно будет заменить слово multiprocessing на его новый аналог.
                                +3
                                Почему TopologicalSorter лежит в functools? Что тут функционального?

                                На правах шутки: Потому что это свалка для вещей, которые не нужны Гвидо.


                                Guido:


                                “I value readability and usefulness for real code. There are some places where map() and filter() make sense, and for other places Python has list comprehensions. I ended up hating reduce() because it was almost exclusively used (a) to implement sum(), or (b) to write unreadable code. So we added built-in sum() at the same time we demoted reduce() from a built-in to something in functools (which is a dumping ground for stuff I don’t really care about :-).”
                                  +1
                                  Не удивлюсь, если это реальная причина. И на фоне возрождения тренда функциональщины оно еще аукнется питону.
                                  +1
                                  Рекомендую почитать отличную статью на LWN -> lwn.net/SubscriberLink/820424/172e6da006687167, если вкратце, то там сейчас баталии идут.
                                    0
                                    почитал. Много информации чтобы переварить.
                                  +1
                                  Ускорены встроенные типы (range, tuple, set, frozenset, list) (PEP-590)

                                  Не смог после прочтения Пепа сделать аналогичный вывод. Не могли бы немного конкретизировать?
                                    0
                                    Действительно, мне стоило углубиться в этот вопрос, а то не очень понятно, что имелось ввиду в описании релиза под «builtins are now sped up».
                                    Если я правильно понимаю, речь идет о том, что благодаря этому соглашению, ускорится производительность вызова, за счет того, что будет создаваться меньше промежуточных структур в процессе. В любом случае, это больше касается C API, а не разработки на CPython. Однако, это если кто-то лучше вник и может вкратце пояснить, будет круто
                                    +8
                                    2. Использовать lstrip, rstrip:
                                    'foobar'.lstrip(('foo',))

                                    Но есть риск удалить больше чем нужно в случае, когда строка начинается с повторения префикса, а надо удалить только один.


                                    Проблема lstrip даже не в повторениях, а в том, что он работает совсем иначе и использовать его как removeprefix/removesuffix нельзя, так что изменение довольно полезное.
                                    >>> 'fbar'.lstrip('foo')
                                    'bar'
                                    >>> 'oooooobar'.lstrip('foo')
                                    'bar'
                                    >>> 'oofbar'.lstrip('foo')
                                    'bar'
                                    
                                      0
                                      Спасибо за уточнение — возможно сэкономит когда нибудь пару часов дебага. Всегда думал что lstrip ищет/обрезает имеено строку, а не символы ведь я ей передаю строку, а не список символов. По мне так не очень явное поведение. Понятно что теперь из за совместимости не сделать, но если уж расматривать аргумент lstrip как итератор символов для удаления, было бы логичнее вместо добавления removeprefix изменить сигнатуру вызова lstrip: захотел удалить префик — передал ['prefix'], захотел любой из списка символов — передал 'symbols'
                                        0
                                        У него в объявлении метода стоит всё-же chars, а не prefix
                                      +11

                                      Самое главно забыли — больше не надо импортировать typing. Теперь можно делать так:


                                      a: list[int] = []
                                        0
                                        Да отличная штука, добавлено в статью
                                        +1

                                        Главное — чтобы больше не было моржовых операторов.

                                          +1
                                          Новый класс functools.TopologicalSorter для топологической сортировки направленных ациклических графов


                                          О! Здорово, а то мне самому пришлось писать.
                                          Если вы не представляет зачем это — представьте вам нужно загрузить куда-то зависимые друг от друга вещи.
                                          Ну например что-то A не может существовать без B.
                                          что-то C не может существовать без A.
                                          Что-то D не может существовать без A и без C.

                                          Топологическая сортировка вам поможет добыть последовательность загрузки B, A, C, D.


                                            0
                                            Типичный пакетный менеджер)))
                                            +1
                                            У вас непонятный стиль маркирования общения с интерпретатором. Если просто снять с экрана, то получится (CPython, PyPy — почти одинаково):

                                            >>> 2+3
                                            5
                                            >>> 2 == 3
                                            False
                                            


                                            а ваши примеры почему-то соответствуют такому:

                                            2+3
                                            >> 5
                                            2 == 3
                                            >> False
                                            


                                            Это сурово анноит, прошу исправить примеры.
                                              0

                                              Объясните кто-нибудь, почему в питоне объединение 2х словарей настолько важно что под него целый оператор добавили?

                                                0
                                                Не то, чтобы прямо очень важно, сколько лет без него нормально обходились.
                                                Но всё-таки:
                                                1. Периодически необходимость объединить два словаря возникает. Сейчас для этого приходится пользоваться костылями типа:
                                                res = dict1.copy()
                                                res.update(dict2)

                                                2. Добавление нового оператора — не такое уж значительное изменение, чтобы для него нужна была очень веская причина.
                                                3. Для множеств подобный оператор уже давно есть, а словари, по сути, просто множества с дополнительными значениями.

                                            Only users with full accounts can post comments. Log in, please.