Новую версию Python многие разработчики ожидали с нетерпением. Кто-то и не ждал, поскольку вполне достаточно было возможностей прежней версии. Но Python 3.12 таки выпустили, сейчас стало известно, что эту ветку будут поддерживать полтора года, а потом для нее станут формировать исправления для устранения уязвимостей — в течение еще трех с половиной лет.
Кроме того, запущен процесс альфа-тестирования Python 3.13, где заявлен режим сборки CPython без глобальной блокировки интерпретатора (GIL, Global Interpreter Lock). Тестировать ветку будут в течение семи месяцев, исправляя ошибки и добавляя новые возможности. Затем еще три месяца — тестирование бета-версий и еще через два месяца появится пред-финальная версия. Но будет потом, а сейчас поговорим о том, что уже есть в руках — о Python 3.12.
Так что мы получили?
Понятно, что в течение года никто не сидел, сложа руки — в новой версии появилось много нового и интересного. Вот список наиболее заметных изменений:
- Улучшена эффективность использования ресурсов многоядерных систем за счет добавления поддержки изолированных субинтерпретаторов и отдельных глобальных блокировок (GIL, Global Interpreter Lock) для разных интерпретаторов внутри процесса (CPython позволяет в одном процессе выполнять запускать сразу несколько интерпретаторов). Правда, сейчас эта новинка доступна посредством C-API, а поддержка Python API будет добавлена в следующей ветке.
- Также добавлена поддержка подсистемы ядра Linux perf в интерпретаторе. Она дает возможность определять имена Python-функций при профилировании при помощи утилиты perf (ранее в трассировках определялись только имена Си-функций).
- Еще одно важное изменение — повышение информативности сообщений об обшибках. Кроме того теперь спектр исключений с предложением рекомендации по устранению опечаток расширен. Вот пример:
sys.version_info
NameError: name 'sys' is not defined. Did you forget to import 'sys'?
somethin = blech
NameError: name 'blech' is not defined. Did you mean: 'self.blech'?
import a.y.z from b.y.z
SyntaxError: Did you mean to use 'from ... import ...' instead?
from collections import chainmap
ImportError: cannot import name 'chainmap' from 'collections'. Did you mean: 'ChainMap'?
- Также продолжается активная работа по оптимизации производительности. Она понемногу движется и есть первые результаты — согласно анонсу производительность стала на 5% выше. Не бог весть что, но тоже неплохо. Повышения удалось добиться благодаря:
- Добавлении поддержки бинарного оптимизатора BOLT, который и повышает производительность на 1-5%.
- Добавлено inline-развёртывание списковых включений (comprehensions). Это нововведение дало возможность ускорить работу со списковыми включениями.
- Размер Unicode-объектов снизили на 8-16 байт.
- Увеличена скорсть операций с регулярными выражениями re.sub(), re.subn() и re.Pattern.
- Ускорено выполнение проверок isinstance() для некоторых протоколов — от 2 до 20 раз.
- Также ускорены функции tokenize.tokenize() и tokenize.generate_tokens().
- Предложен более компактный синтаксис аннотирования типов для обобщенных классов и функций. Вот пример:
def max[T](args: Iterable[T]) -> T:
...
class list[T]:
def __getitem__(self, index: int, /) -> T:
...
def append(self, element: T) -> None:
- Появился новый способ определения псевдонимов типов при помощи выражения type. Еще пример:
type Point = tuple[float, float]
type Point[T] = tuple[T, T]
- Также в модуле typing добавлен новый декоратор override. Он информирует системы проверки типов о том, что метод в подклассе предназначен для переопределения метода или атрибута в суперклассе. И еще один пример:
class Base:
def log_status(self) -> None:
...
class Sub(Base):
@override
def log_status(self) -> None: # Ok, переопределяет Base.log_status
...
@override
def done(self) -> None: # Система проверки типов выявит ошибку
…
- В новой версии увеличена гибкость разбора f-строк (форматируемые литералы с префиксом 'f'), что открыло новые возможности, включая возможность указаний любых допустимых для Python выражений, включая многострочные выражения, комментарии, обратные слэши и escape-последовательности для Unicode. Во внутренней строке можно повторно использовать двойные кавычки, не применяя одинарные. А еще увеличена информативность сообщений в f-строках, в которых теперь указывается точное место в строке, вызвавшее ошибку. Вот пример:
print(f"This is the playlist: {"\n".join(songs)}")
print(f"This is the playlist: {"\N{BLACK HEART SUIT}".join(songs)}")
print(f"This is the playlist: {", ".join([
... 'Take me back to Eden', # My, my, those eyes like fire
... 'Alkaline', # Not acid nor alkaline
... 'Ascensionism' # Take to the broken skies at last
... ])}")
- Улучшена и безопасность. Так, встроенные реализации алгоритмов SHA1, SHA3, SHA2-384, SHA2-512 и MD5 в hashlib заменены на формально верифицированные варианты от проекта HACL* (встроенные реализации применяются только если отсутствует OpenSSL).
- Добавлена защита от переполнения стека в Cpython.
- В модуле pathlib.Path реализована поддержка подклассов, а в модуле os теперь расширена поддержка Windows. В частности, для этой ОС добавлена поддержка методов os.listdrives(), os.listvolumes() и os.listmounts(), а также повышена точность os.stat() и os.lstat().
- Кром того, в модули sqlite3 и uuid добавлены интерфейсы командной строки («python -m sqlite3» и «python -m uuid»).
- Кроме новых возможностей разработчики решили почистить некоторые старые, которые уже не нужны. В частности, убраны модули asynchat, asyncore, smtpd, imp и distutils (модуль distutils можно использовать из пакета setuptools). Убраны устаревшие методы в unittest. Избавились и от устаревших и некорректно работающих функций, классов и методов. В первую очередь, это locale.format(), io.OpenWrapper, ssl.RAND_pseudo_bytes(), ElementTree.Element.copy(), hashlib.pbkdf2_hmac(), gzip.GzipFile.
- Удалена поддержка таких браузеров, как Grail, Mosaic, Netscape, Galeon, Skipstone, Iceape, Firebird, и Firefox до версии 36.
Другие полезные материалы
Комментарии (68)
Finesse
03.10.2023 01:44-2Удалена поддержка таких браузеров, как…
Каким образом Python поддерживает браузеры?
blueboar2
03.10.2023 01:44Может открыть веб-страницу, и указать, в каком именно браузере (в модуле webbrowser)
marat2509
03.10.2023 01:44+1https://habr.com/ru/companies/selectel/articles/761914/#comment_26022506
https://docs.python.org/3/library/webbrowser.html
jpegqs
03.10.2023 01:44+3A "basic JIT compiler for short regions" might be added to CPython 3.12 to compile only tiny sections of specialized code...
Так JIT добавили или нет, или Гвидо обманул? Помню старые новости, где это обещалось.
Sap_ru
03.10.2023 01:44+6Нет. Забоялись. Пришлось перетрусить много op-codes (а это само по себе ой-ой-ой изменение), притулить оптимизатор (что тоже ой-ой-ой), и ещё кучу всего. Поэтому всю подготовительную работу, вроде, сделали, а сам JIT добавлять не стали и перенесли на следующий релиз, так как он задержал бы выход этого релиза.
Могут и дальше задерживать, так как там сейчас (наконец-то) очень серьёзная работа по избавлению GIL началась, что требует переписывания кучи кода, подсистем и библиотек. И пока всё идёт к тому, что блокирующие изменения будут просто откладываться до выпуска интерпретатора с режимом без GIL, так потом всё равно всё переписывать нужно будет.
Sap_ru
03.10.2023 01:44+9"Добавлено inline-развёртывание списковых включений (comprehensions). Это нововведение дало возможность ускорить работу со списковыми включениями."
Вот эта штука ускоряет многие часто используемые вещи вроде list(some_generator) вещи в два раза и больше. 5% прироста это они поскромничали, на некоторых задачах там 15% прироста. Особенно если переписать циклы и проверки под новые присвоения переменных в выражениях.
Вместе в новым оптимизатором в сумме очень хороший прирост получается.CrazyElf
03.10.2023 01:44+1Если кого-то беспокоит скорость работы циклов, то нужно либо менять алгоритм, либо переделать код под Numba, эффект будет гораздо больше.
Sap_ru
03.10.2023 01:44+4А почему о ещё одной киллер-фиче не написали?
while( ( a:=some_data_read_method() ) is not None ):
print(a)
Вместе с новыми дженериками, f-строками (которые больше не кривой велосипед, а именно то, что должно быть) и foward types язык снова стал современным. Не хватает только null-check оператора.AMDmi3
03.10.2023 01:44+4Потому что assignment expressions появились ещё в 3.8?
ritorichesky_echpochmak
03.10.2023 01:44+9А коробит от := до сих пор, как и от for...else - лютая же наркомания
Yuribtr
03.10.2023 01:44+3Личное ИМХО: оператор "морж" неплохо так сокращает обьем кода и удобен для валидации большого количества параметров, стараюсь его использовать везде где поддерживается:
def process_message(message): if not (value := extract_value(message)): raise ValueError('Value is absent') if code := extract_code(message): process_code(code) ...
А по поводу for ... else есть кейсы в которых значительно сокращает объем кода. Например вот такая задача по очистке списка от невалидных данных. Ее конечно можно решить разными способами, но вот мне такое решение показалось более изящным и понятным:
list_a = [ [1, 2, 3, 4], [1, 2, '3', 4], [1, 2, 3, 4], ] list_c = [] for list_b in list_a: for item in list_b: if not isinstance(item, int): break else: list_c.append(list_b) print(list_c)
iliazeus
03.10.2023 01:44+16В вашем примере очень неочевидный control flow, из-за чего не сразу понятно, что он вообще делает. Мне кажется, вот так и короче, и понятнее:
for list_b in list_a: if all(isinstance(item, int) for item in list_b): list_c.append(list_b)
Так что ваш пример получился не в пользу
for-else
:)leshabirukov
03.10.2023 01:44-3А можете за один проход, чтобы вот такое тоже работало?
def gen4(): yield from range(4) list_a = [ (1, 2, 3, 4), [1, 2, '3', 4], [1, 2, 3, 4], gen4() ] list_c = [] for list_b in list_a: if all(isinstance(item, int) for item in list_b): list_c.append(sum(list_b)) print(list_c)
[10, 10, 0] # ,а хотеть [10,10,6]
( Код @Yuribtr -а тоже опустошает генератор )
iliazeus
03.10.2023 01:44+2Я не спорю, что условие задачи можно поменять так, чтобы именно тот синтаксис был уместным. Более читаемым он от этого не станет.
Можно написать так
for iterator in iterators: total = 0 for item in iterator: if isinstance(item, int): total += item else: break else: result.append(total)
Можно так
for iterator in iterators: total = 0 for item in iterator: if not isinstance(item, int): break total += item else: result.append(total)
Хотя мне больше нравится такой вариант:
for iterator in iterators: valid = True total = 0 for item in iterator: if not isinstance(item, int): valid = False break total += item if valid: result.append(total)
В нем одновременно есть и "отрицательное условие"
if not ...: break
(потому что именно так выглядит привычный паттерн проверки предусловий), и нет визуальной путаницы, к чему именно относитсяelse
(повторюсь, по другим языкам мне намного привычнее ассоциировать его с ближайшим if, а не с циклом).leshabirukov
03.10.2023 01:44+1Да, наверное так - лучше всего. Если честно, я и сам не придумал, как сделать чистый pipe. Понятно, что в общем случае, последующий конвейер должен ждать, пока не станет ясно, что строка валидная.
ritorichesky_echpochmak
03.10.2023 01:44Если там ТАК воткнут генератор, то там уже независимо от количества проходов всё плохо. Потому что дальше кто-то другой захочет взять этот же массив, передать его куда-нибудь ещё и... ой, всё сломалось.
Генератор в данном случае будет перебран весь, т.е. смысла от непосредственно yield тоже не особо видно. На этом можно спокойно добавить одну строчку и перестать страдать ради... ачивки самого плохо сопровождаемого кода и "незаменимого специалиста который один знает как это всё классно работает"for list_b in list_a: arr = list(list_b) if all(isinstance(item, int) for item in arr): list_c.append(sum(arr))
leshabirukov
03.10.2023 01:44Ну, это может быть библиотечная функция, которая, в частности, обрабатывает файл на проходе посимвольно, еще и фильтруя строки по какому-то принципу.
ritorichesky_echpochmak
03.10.2023 01:44Так посимвольно или построчно? Там есть нюанс: читать файл побайтово - дико дорого и почти бессмысленно. Читать побайтово по сети - ещё дороже. Из базы данных - вообще безумие. Без практически ценной имплементации (какого-то реального кейса) этих костыликов, которая бы ЯВНО выигрывала у читаемых нормально вариантов всё это бессмысленно
Yuribtr
03.10.2023 01:44Да, согласен что мой пример может быть упрощен. В реальном приложении в циклах наверняка будет логгирование, дополнительный процессинг значений, конвертация значений, отлов исключений. Ну хотя бы так:
def process_codes(codes_list: list): result = [] for codes in codes_list: for code in codes: if not isinstance(code, int): logging.warning(f'Found wrong code {code}') break else: result.append(codes) return result
На самом деле такой оператор хорошо так применять в бизнес логике по предобработке и конвертации значений из формата одной системы в формат другой системы.
В вашем примере очень неочевидный control flow, из-за чего не сразу понятно, что он вообще делает
Ну это вопрос привычки. Привыкаешь к такому синтаксису и потом легко читать.
iliazeus
03.10.2023 01:44def validate_codes(codes): for code in codes: if not isinstance(code, int): warn(f"wrong code: {code}") return False return True def extract_valid_codes(codes_list): return [c for c in codes_list if validate_codes(c)]
Ну это вопрос привычки. Привыкаешь к такому синтаксису и потом легко читать.
Я не спорю, что я не привык. Но мне кажется, что это одна из наиболее непривычных фич Python, и я не уверен, что эта непривычность оправдана.
ritorichesky_echpochmak
03.10.2023 01:44Сокращает, но вот удобнее читать и искать в этой каше что откуда почему - сильно спорный вопрос. Очень не очевидно, почему переменная проинициализированная в блоке проверки видна вне блока. Эта абракадабра - последнее место куда люди будут смотреть в попытках понять, откуда спустилась эта переменная. Давайте тогда вообще забьём на область видимости переменных
Второй пример вообще выглядит как издевательство
for list_b in list_a: if all(isinstance(item, int) for item in list_b): list_c.append(list_b)
А если Python не единственный язык разработчика (а возможно и не основной), то всё становится сильно трагичнее
iliazeus
03.10.2023 01:44+6Иронично, что мы написали прям дословно одинаковый код в одновременных комментариях :)
Еще одно подтверждение тому, что такой вариант куда более интуитивен, чем
for-else
.AMDmi3
03.10.2023 01:44+1Любая инвертированная логика неинтуитивна, а for..else скорее всего задумывался для прямолинейной логики поиска, которая выглядит вполне логично:
for x in iterable: if predicate(x): break else: raise NotFoundException() # work with x
И я бы даже предпочёл её более современному функциональному коду, который в питоне получается отвратителен:
if (x := next(filter(predicate, iterable)), None) is None: raise NotFoundException()
if (x := next((i for i in iterable if predicate(i)), None) is None: raise NotFoundException()
try: x = next(filter(predicate, iterable)) except StopIteration: raise NotFoundException()
from more_itertools import first_true # лучше, но нужен внешний модуль if (x := first_true(iterable, pred=predicate)) is None: raise NotFoundException()
iliazeus
03.10.2023 01:44+1Ваш первый вариант мне не нравится тем, что для меня ключевое слово
break
не несет смысл возврата значения. Если бы в вашем примереpredicate
не назывался так очевидно, я бы сначала подумал, что эта функция как-то меняет или потребляет значения изiterable
, и возвращает флаг "дайте мне еще данных".Наверное, это дело привычки. Я не привык писать на Python, поэтому паттерны с
for-else
не узнаю сразу.В идеали, я бы хотел иметь
find
в стандартной библиотеке, работающий какmore_itertools.first_true
. И писал бы так:x = find(iterable, predicate) if x is None: raise NotFoundException()
А из ваших вариантов мне ни один не нравится, что с
for-else
, что другие. Если выбирать только из существующих способов, сделал бы как-то так:x = filter(predicate, iterable) x = next(x, None) if x is None: raise NotFoundException()
Но все равно некрасиво.
fireSparrow
03.10.2023 01:44Я бы написал так:
found = any(predicate(x) for x in iterable) if not found: raise NotFoundException()
или так
found = any(map(predicate, iterable)) if not found: raise NotFoundException()
iliazeus
03.10.2023 01:44Наверное, из нашей ветки это не очень понятно, но я (и @AMDmi3, думаю, тоже) предполагал, что найденный элемент будет еще где-то потом использоваться. В ваших вариантах только проверяется наличие элемента:
any()
возвращаетbool
.Грубо говоря, представьте, что после всех наших отрывков кода стоит
return x
.
ritorichesky_echpochmak
03.10.2023 01:44Даже хотя бы
x = next(filter(predicate, iterable), None) if x is None: raise NotFoundException()
будет куда лучше, чем эти канделябры. Хотя в других языках было бы что-то вида
x = next(filter(predicate, iterable)) ?? throw NotFoundException() # в пайтоне ожидаешь что-то вида x = next(filter(predicate, iterable), None) or raise NotFoundException()
потому что в одну строку - хуже читается. Почему из пайтона нельзя вместо None бросить исключение в next - куда более интересный вопрос, чем все эти моржекостыли
NN1
03.10.2023 01:44В C# “out var” работает похожим образом и ничего, удобно и читаемо.
Может потому, что есть ещё «out» за который легко зацепиться глазами.
ritorichesky_echpochmak
03.10.2023 01:44out var часто не рекомендуют использовать, если есть другие варианты. А с появлением кортежей они есть. А до их появления рекомендовалось вернуть объект, если уж надо прям много и разного вернуть. Плюс в C# протерянная переменная, или объявленная в двух местах или с не тем типом громко упадёт ещё при сборке, т.е. настолько забагованную вещь ты не сможешь отдать в прод даже если тесты продолбаны
NN1
03.10.2023 01:44Это да, объявить повторно не получится.
Я тут поискал может MyPy как-то может спасти ситуацию но не нашёл.
Разве что с аннотацией typings.Final объявить.
Yuribtr
03.10.2023 01:44+1Очень не очевидно, почему переменная проинициализированная в блоке проверки видна вне блока
Разверните свою мысль пожалуйста. Может у меня глаз замылился, не вижу проблемы
Второй пример вообще выглядит как издевательство
Чуть выше ответил. Да, чтобы убрать лишнее - сильно упростил пример. Но как вы понимаете в реальном приложении будет много чего в этих циклах. Но опять же это дело вкуса и сформировавшейся привычки. Просто хотел отметить что ваша фраза:
А коробит от := до сих пор, как и от for...else - лютая же наркомания
реально вызвала недоумение. Этот синтаксический сахар реально помогает, улучшая читаемость. Но если не нравится - вас никто не заставляет пользоваться )
ritorichesky_echpochmak
03.10.2023 01:44+1Давайте я вас лучше наведу на мысль: почему бы тогда этому коду не быть корректным
for variable in array: pass print("Latest: ", variable)
Аргументация должна быть немножко интереснее, чем "это синтаксический сахар, значит надо пользоваться". Я пишу на .NET/C#, TypeScript (по сути JS), немного Kotlin... и потом переключаюсь на какой-нибудь скрипт для отчётов, а там вот такие синтаксические извращения не поддающиеся никакой логике, не переводящиеся на человеческий язык никаким боком. Как это читать? Для всех переменных из массива считаем что-то, иначе... какое иначе? Что иначе? Почему иначе? Иначе это нельзя было назвать хотя бы? Может это finally? Хотя там много других прекрасных слов можно было найти: another, otherwise... нейтив спикеры могли бы подсказать много куда более удачных вариантов
Я уже слишком стар чтобы замыливать глаз на вещи, которые создают больше проблем, чем решают. Иногда лучше написать лишнюю строку и получить более прозрачный алгоритм, который может посмотреть кто угодно (включая специалистов не являющихся программистами, а являющихся физиками, биологами и т.д.) без попытки угадать, какие сайдэффекты привносит сахар
Mingun
03.10.2023 01:44Давайте я вас лучше наведу на мысль: почему бы тогда этому коду не быть корректным
Вам довольно прозрачно намекнули, что в изначальном примере кода c
for ... else
нет «переменной, проинициализированной в блоке проверки и видной вне блока». Так что вот и не понятно, что в этом синтаксисе вас не устраивает.ritorichesky_echpochmak
03.10.2023 01:44-1В посте на который я изначально писал что очень не очевидно почему переменная видна вне блока, есть первый пример, про моржа
if not (value := extract_value(message)): raise ValueError('Value is absent')
и второй, про for...else. И я в ответе достаточно очевидно отделил ответ на второй пример. Написать про второй пример, что он второй пример - это не достаточный для кого-то намёк что он второй? Серьёзно? Тогда `:=` действительно наименьшая из проблем...
ababo
03.10.2023 01:44while( ( a:=some_data_read_method() ) is not None ):
Киллер фичи, которые мы заслужили...
ritorichesky_echpochmak
03.10.2023 01:44+2Убраны устаревшие методы в unittest
А там что-то не устаревшее есть? Параметризованные тесты оно не умеет и в целом после Pytest выглядит как что-то максимально бесполезное. Лучше бы Pytest в основную кодовую базу втащили
dolfinus
03.10.2023 01:44+1pytest от этого станет медленнее развиваться, релизы же будут вместе с интерпретатором. И с поддержкой предыдущих версий Python будут сложности.
0Bannon
03.10.2023 01:44Ну, вот, а говорят питон простой язык. С каждым годом столько наворотов.
iliazeus
03.10.2023 01:44+1Так наоборот же, в этом релизе многое стало проще:
убрали депрекейтнутые функции (unittest, webbrowser)
добавили более адекватный синтаксис (параметры дженериков, type, override)
убрали неочевидные ограничения, о которые все спотыкались (парсинг f-строк)
увеличили полезность сообщений об ошибках
iuabtw
03.10.2023 01:44+10Мне кажется, что зря они f-строки ещё дальше расширяют. Некоторые коллеги в них начинают творить непотребства, функции вызывать, какую-то логику писать, в общем превращают питон в PHP
iliazeus
03.10.2023 01:44+6Мне кажется, что это стоит решать скорее насаждением стиля кода в команде. А для самого языка лучше быть консистентным - допускать в них любые выражения, без произвольных ограничений.
Ограничения f-строк меня уже давно раздражали, если честно. Особенно невозможность использовать бекслеши, или одни и те же кавычки.
iuabtw
03.10.2023 01:44+3А можете показать какой-нибудь ежедневный пример f-строки?
Я просто, как старовер, не люблю в них писать ничего сложнее условного
f"hello {var}"
. Интересно, как ими пользуются коллеги по цеху в более сложных случаях.Про код стайл согласен. Была бы возможность - настроил бы линтеры по вкусу.
iliazeus
03.10.2023 01:44+2Я не очень много пишу именно на Python, больше на JS/TS, в котором таких ограничений нет. Поэтому спотыкаюсь в простых случаях:
# здесь нужны другие кавычки f"order id: {order["id"]}" # здесь нельзя бекслеш f""" some header {'\n'.join(rows)} """
Конечно, все это сразу же подсвечивается IDE и правится. А второй случай у меня чаще всего возникает в кустарных одноразовых скриптах, когда я мало забочусь о стиле кода, и нужно просто что-то быстро вывести в нужном формате. Но, тем не менее, немного раздражает.
NN1
03.10.2023 01:44+1А разве в первом случае в JS не нужны другие кавычки тоже ?
Обратную косую черту можно обойти дополнительной переменной хотя конечно и не так удобно.
nl = '\n' print(rf""" {nl.join(["a", "b"])} """)"""
iliazeus
03.10.2023 01:44А разве в первом случае в JS не нужны другие кавычки тоже ?
В том и дело, что нет:
> var order = { id: 123 }, s = `order: ${order[`id`]}`; s 'order: 123'
Понятное дело, что и случаев таких в JS/TS меньше, потому что кавычки для форматирования - это не обычные одинарные и двойные, и потому что в "объекты-словари" можно ходить просто через точку (
order.id
).Обратную косую черту можно обойти дополнительной переменной хотя конечно и не так удобно.
Понятно, что можно обойти. Но, если честно, в Python мне чаще, чем во многих других языках, приходится искать вот такие обходные пути. В треде выше вот огорчился, что нет встроенного
find(iterable, predicate)
, тоже приходится как-то обходить.
squaremirrow
03.10.2023 01:44-1(параметры дженериков, type, override)
А кто-то этим пользуется в Питоне?
Вся эта возня с типами — она нужна исключительно для удобства разработки. Попытка превратить Питон в язык с таким же разнообразием средств типизирования, как в строго типизированных языках, мне кажется ошибочной.
iliazeus
03.10.2023 01:44+2Так без всего этого разрабатывать как раз бывает неудобно.
Вот тут выше только что, опять-таки, обсуждали, что в Python нужно либо брать из библиотеки, либо реализовывать самому функцию
find(iterable, predicate)
. Ее, например, без дженериков адекватно не типизируешь. И так с очень многими библиотечными, "не-бизнесовыми" функциями.
kefiiir
03.10.2023 01:44+1" Во внутренней строке можно повторно использовать двойные кавычки, не применяя одинарные. "
меня это прямо пугает, и еще интересно сколько % подсвечевалок синтаксиса это умеет
print(f"This is the playlist: {"\n".join(songs)}")
iliazeus
03.10.2023 01:44+1Все, что сложнее наивных регулярок, должно подсвечивать нормально. Хабр вот справляется:
f"foo {x["bar"] + 1} baz"
un_m_nj
03.10.2023 01:44Решил проверить прибавку производительности новой версии python.
Запустил код на 4х версиях python (3.7, 3.9, 3.11, 3.12)import time
times = []def check():
strt = time.time()
sum_: int = 0
for x in range(1_000_000_000):
sum += x
times.append(time.time() — strt)for x in range(5):
check()
print(times, sum(times) / 5)Python 3.7.0: 37,76 с
Python 3.9.0: 34,83 с
Python 3.11.0: 32,28 с
Python 3.12.0: 41,22 сНе смог понять, почему простой цикл на новой более оптимальной версии выполняется медленнее, чем на 3.7
valentinoshm
03.10.2023 01:44Предложен более компактный синтаксис аннотирования типов для обобщенных классов и функций. Вот пример:
def max[T](args: Iterable[T]) -> T:
Я правильно понимаю, что это просто чтобы
T = TypeVar('T')
не писать?Появился новый способ определения псевдонимов типов при помощи выражения type. Еще пример:
type Point = tuple[float, float]
В чем отличие от
Point = tuple[float, float]
без type?iliazeus
03.10.2023 01:44+3TypeVar
в целом выглядел как костыль. Рад, что от него избавляются.Еще, например, forward references поддерживаются без костылей:
# старый костыль # `: TypeAlias` можно не писать, но тогда # это выглядит еще больше как просто строка FooStr1: TypeAlias = "Foo1[str]" T = TypeVar('T') class Foo1(Generic[T]): ... # новый синтаксис type FooStr2 = Foo2[str] class Foo2[T]: ...
siyet
03.10.2023 01:44А почему не упомянули про фабрику жадных корутин?
Там обещают прирост производительности до 50%
https://docs.python.org/3.12/library/asyncio-task.html#asyncio.eager_task_factory
CrazyOpossum
Это шутка? Или как вообще браузеры поддерживались в языке?
DevAdv
https://docs.python.org/3/library/webbrowser.html
Nansch
Ну это же программная поддержка через библиотечную функцию. На уровне языка никакие браузеры, конечно же, не поддерживаются.
CrazyElf
Стандартные библиотеки питона - это его неотъемлемая часть.