Comments 75
Эти нововведения только лишь мне одному кажутся сомнительными ?
Аргументирую.
Моржовый оператор открывает дорогу в ад. Будет та же ситуация, что и в Си — поди догадайся в каком порядке вычисляются все подвыражения. Нужна однозначность, а она обеспечивается кодом в "старом" стиле. Если же мы говорим про эффективность интерпретации, ну, так интерпретатор сделайте умным — с JIT, blackjack и куртизанками.
format v2.0 — очень сомнительно. Стало меньше писанины? Ну, немного. Стоило? Нет.
continue в finally — выглядит как возможность создавать недостижимые участки кода. Зачем? В проекте в принципе не должно быть недостижимого кода.
Позиционные аргументы. Ну, оч.странно. Реально у кого-то от этого болело? Проблем с передачей **kwargs между функциями не будет ?
И только пп.4 и 5 выглядят более-менее полезными
По-моему markdown сломал вам нумерацию
format v2.0 — очень сомнительно. Стало меньше писанины? Ну, немного. Стоило? Нет.
Стоило чего? Разработки? Ну, python это open source, так что чуваку, который законтрибутил ок, наверное. А какие минусы?
continue в finally — выглядит как возможность создавать недостижимые участки кода. Зачем? В проекте в принципе не должно быть недостижимого кода.
Аналогичное же раньше делалось через bool переменную, так что какая разница?
Позиционные аргументы. Ну, оч.странно. Реально у кого-то от этого болело? Проблем с передачей **kwargs между функциями не будет ?
Это стандартизация такая. В CPython методах такое было, а в обычном python нет. Вот исправили.
Первый пункт — это наоборот счастье. Сколько приходится сталкиваться с
b = myfunc(a)
while b > 0:
a += 1
b = myfunc(a)
А теперь я могу написать
while b := myfunc(a) > 0:
a += 1
И кто бы что не говорил про оптимизацию, про костыли вида функции возвращающей значение И изменяющей его же в самой функции, это хорошо. А вот остальное — да, не могу сказать, что прям что-то кардинальное. Форматирование в строках я честно говоря вообще не использую. Дебагпринты? Сомнительный резон.
не могу согласиться, к сожалению, богатый опыт написания кода на С/C++ говорит о том, что это потенциальное UB. В Вашем же примере — первый сниппет четко понятен. Второй — все равно будет внутри преобразован в первый пример, но при этом и выглядит ужасно, и вводит новую сущность, и когнитивная нагрузка на разработчика выше.
Единственное, где бы, ВОЗМОЖНО, я одобрил применение такого приема — это list comprehension и lambda, да и то не факт
while True:
b = myfunc(a)
if b <= 0: break
a += 1
Не сильно лучше, чем через :=. Точнее имхо хуже
Если уж за красоту бороться, то можно пойти дальше (хоть это и явно медленнее):
import sys
for a in range(sys.maxint): # Python 3 range
b = myfunc(a)
if b<=0: break
Кстати, я всегда жалею, что в Python нет обратного if, он так хорошо читается, как раз в таких коротких примерах.
do:
b = myfunc(a)
a += 1
while b <= 0
Форматирование в строках я честно говоря вообще не использую. Дебагпринты? Сомнительный резон.
История эволюции форматирования строк в Python полна боли и отчаяния. Интерполяция, которую завезли в 3.6 — это вершина этой эволюции и в большинстве случаев лучший и к тому же самый быстрый способ (для него сделали отдельную инструкцию в байткоде) форматировать строки. Попробуйте его использовать. Это правда круто и после него не хочется использовать format
и %
. :)
Касательно новой "отладочной фичи", совсем недавно это использовал в примерно таком коде с pytest:
...
sizes = ...
ndims = ...
...
ids = [f'{size=}|{ndim=}' for size, ndim in zip(sizes, ndims)]
...
metafunc.parametrize('size, ndim', [sizes, ndims], ids=ids)
collected 83 items
test_foo[size=100|ndim=2] .....
test_foo[size=100|ndim=3] .....
...
Вот только нужно понимать, что format
и %
можно использовать для "отложенной" интерполяции, а f-строки — нет, всегда вычисляются сразу на месте. Отложенная интерполяция полезна, чтобы иметь возможность сохранить шаблон, передать, писать лог с параметрами — в последнем случае особенно хорошо экономится на бесполезной интерполяции, если уровень логгирования окажется ниже минимального.
Я не предлагаю использовать f-строки там где нужно отложенное форматирование, для логгирования или шаблонов. Это, очевидно, специфические случаи.
logger.info('hello, %s', username) # logging
logger.info('hello, {}', username) # loguru
Но в случае прямого форматирования строк нет никаких причин отказываться от f-строк.
'hello, %s' % username
'hello, {}'.format(username)
f'hello, {username}'
Код получается более чистый, лаконичный и понятный (если, не писать в строках длиннющие выражения, конечно).
Это:
if (match1 := pattern1.match(data)):
result = match1.group(1)
elif (match2 := pattern2.match(data)):
result = match2.group(2)
else:
result = None
Вместо:
match1 = pattern1.match(data)
match2 = pattern2.match(data)
if match1:
result = match1.group(1)
elif match2:
result = match2.group(2)
else:
result = None
Выглядит как попытка добавления синтаксического мусора в язык. Количество логики в данном случае не уменьшилось, зато теперь надо парсить глазами содержимое между скобок.
- Думаю нагляднее был бы пример с условием в finally
if i > 0:
continue
print('test')
1. Новый оператор требует, как минимум, тщательного объяснения его применимости. Даже приведенный пример с массивом, сколько людей способно понять, почему в этом случае он не сработает? Извращенный ум и шаловливые рученки могут породить еще массу вариантов, которые нужно будет проверять, прежде чем вставлять в реальный код. И кто выиграет от такого «улучшения»?
2. Было же простое и понятное правило, сначала идут позиционные, потом именованные аргументы. Зачем и кому потребовалась эта ужесть? Зачем в список параметров функции помещать что — то кроме параметров этой самой функции?
4. Поправьте меня, если я ошибаюсь, но есть просто dict и есть OrderedDict, который помнит порядок вставки. Если для второго — ок, наверное это кому — то нужно, то для первого ценность нововведения сомнительна, на мой взгляд.
П. п. 3 и 5 особой антипатии не вызывают, хотя, лично для меня, и особой ценности не представляют.
4. начиная с 3.7, ключи в словаре упорядочены по порядку добавления — stackoverflow.com/questions/39980323/are-dictionaries-ordered-in-python-3-6.
Соответственно, обратный порядок тоже может быть полезен
Ок, кому — то чисто позиционные параметры нужны, я, хоть и не согласился, но понял «зачем». Чего я точно не понимаю, и вообще, слегка в шоке, «почему так»? Ну приспичило вам вам запретить обращение к параметру по имени, ну так возьмите и пометьте каждый такой параметр каким нибудь значком, или даже слово служебное придумайте. Все остальные параметры тусуем как хотим, а этот желаем видеть только на третей позиции, к примеру, и ни как иначе.
> 4.…
То, что в текущей реализации словарь оставляет значения в порядке вставки, это, скорее детали реализации, нежели дизайна языка. На мой взгляд, плохая идея — использовать эту особенность в чем — то, что будет запускаться не только вами и не один — два раза.
формат — довольно полезная ИМХО фича, особенно если при переименовывании переменной (нет дублирования текста, нет дублирования работы)
continue — это в примере нет условия, с условием сразу понятна полезность
Зато, если порядок выражений чётко определён (через зависимости в and или or), получается колоссальное сокращение в коде вида
if (a:=f1()) and (b:=a.f2()) and (c:=f3(b,a,444)) > 10 or (c:=f4(x,y,z)) > 0:
....
А такие конструкции очень часты при операциях, например, со сложными структурами данных и опциональными параметрами в них.
И в такой конструкции (абстрагируемся от Питона) мы гарантированно получаем два поведения в зависимости (как в сях) от опции компилятора — оптимизировать вычисление логического выражения, если его результат уже ясен, или высчитывать все равно каждое его подвыражение. Чегой-то я не хочу в таком мире жить...
В C всегда и для всех, для && и ||, если результат выражения однозначно ясен по левой части, правая не вычисляется.
В Python аналогично для and и or. Цитата из документации:
> The expression x and y first evaluates x; if x is false, its value is returned; otherwise, y is evaluated and the resulting value is returned.
> The expression x or y first evaluates x; if x is true, its value is returned; otherwise, y is evaluated and the resulting value is returned.
> абстрагируемся от Питона
Зачем нам абстрагироваться от Питона? Мы пишем на вполне конкретном Питоне.
Окей, это родовая травма от Паскаля
https://www.freepascal.org/docs-html/prog/progsu4.html
Но в любом случае — такой код я не считаю best practice
1) Ну наконец-то догадались сделать, и даже оператор присвоения из Паскаля — не слишком плохой вариант
2) Выглядит как ересь, или призыв сотоны однострочником. Весь мир двигается к именованным аргументам
3) Странная у вас интерполяция, явно js покусал
4) А этого не было?!
5)… все равно мета возможности рубей сломают мозг с большей вероятность (читай: руби тут мощнее)
6) Ну и хорошо
Однозначно, чем дальше — тем хуже!
Пункт 1 это победа
Вопрос тогда только один — а куда, на какой язык перекатываться? Пайтон привлекал и привлекает тем, что у него батарейки включены. И он очень хорошо заменяет баш для задач администрирования. Ну, и весь ML на нем.
автоматизация (сисопс, девопс, гитопс....)
ML
написание простых http сервисов
P.S. Сам, правда, еще не пробовал ;)
Спасибо за обзор. В чужом коде буду узнавать, если увижу. У меня самого энтузиазма новые фичи не вызвали.
def my_func(a, b, /, c, d, *, e, f):
return a+b+c+d+e+f
my_func(1, 2, 3, 4, 5, 6)
Это вообще ужасно выглядит. Как будто у функции 8 параметров, но указывать надо 6.# так делать НЕ НАДО
a = 5
d = [b := a+1, a := b-1, a := a*2]
А вот и задачки для горе-собеседований подъехали.А когда порядок элементов словаря стал определённым, что понадобился reversed() или это для OrderedDict() ?
С версии 3.7 Python'ий dict
помнит порядок вставки своих элементов.
Dictionaries preserve insertion order.
Словари сохраняют порядок вставки элементов.
На самом деле… порядок вставки стал запоминаться ещё с версии Python 3.5 или 3.6, в с версии Python 3.7 его сделали обязательной частью спецификации языка.
При том, что вы вставляете в одном, а получаете в обратном. Этот порядок не случаен, а как раз вполне себе определён. При последовательных вызовах reversed()
на одном и том же словаре вы будете получать один и тот же результат. А раньше вообще никакой порядок не гарантировался.
reversed([a for a in dict]) равен [a for a in reversed(dict)]
А, мне просто показалось, что вы мне отвечали (у меня были проблемы с приходом уведомлений об ответах на почту и я в попытках исправить проблему поставил лишние галочки в настройках, в результате чего на почту стали приходить уведомления обо всех комментариях в теме, а не только о тех, которые являются ответом мне. Но сразу я этого не заметил и получилось так, что я написал комментарий, а минуту спустя на него прилетел «ответ»). Так-то, конечно, вы целиком и полностью правы.
с 3.7 это гарантируется официально:
What’s New In Python 3.7
the insertion-order preservation nature of dict objects has been declared to be an official part of the Python language spec.
Чой-то хабр сгрыз мой ответ.
Поэтому дублирую.
Только вот не задача. Ядро языка должно быть минимальным. Так сказать — минимальный набор возможностей для решения максимального количества задач. Потому что если мы ядро языка раздуваем, то как выше коллега заметил — компилятор/интерпретатор языка становится сложнее и действительно нужные фичи становится сложнее добавлять. + Скорость интерпретации/компиляции падает (отличный пример — скорость компиляции с++, можно успеть состариться, пока напичанный на нем проект соберётся) + сложность автоматической кодогенерации (а кто сказал, что она не нужна?)
А самое неприятное, что каждая не очень продуманная фишка языка приводит к новым неочевидным эффектам.
Вот в сообщении ttpss://habr.com/ru/post/483276/#comment_21108246 очень хороший пример. И не надо говорить, что адекватные люди такой код писать не будут, ок?
Я уж не говорю, что сравнивать естественные языки, на которых мы говорим, и языки программирования немного странно. Первые действительно развиваются, но и стоимость изменений в них не такая большая, как в ЯП. Лучше тогда уж сравнивать с искусственными языками. Ну, тем же эсперанто. И сильно ли он популярен? Была на него мода… Но вроде все уже пришли к тому, что язык интернационального общения — ломаный английский.
И смотрите какая интересная штука. Принципиально — за последние лет 40 ничего нового не придумали. Циклы? Так они и тогда были. Функции? Классы? Ввод-вывод? Ну, разве что ФП пошло в массы, но это как-то очень совпало с распространением действительно распределенных систем. Ну, и какие тогда реальные фичи внедрять, кроме синтаксического сахара?
Ну, и какие тогда реальные фичи внедрять, кроме синтаксического сахара?
Касательно CPython, думаю, преодоление проблем/наследия GIL и отсутствия полноценной многопоточности, реализация JIT с опциональной статической типизацией. В общем, двигаться в сторону повышения производительности, потому как с удобством и скоростью программирования на Python уже сейчас всё очень хорошо.
А в синтаксическом сахаре я не вижу ничего плохого, если он улучшает читабельность кода и повышает продуктивность разработчика.
Наши точки зрения аналогичны вкусам людей, одни из которых предпочитают стиль минимализма, а другие — романтизма или барокко. Одни будут стоять за чистоту и практичность ("вот зачем в эти смартфоны добавили сканер биометрии, когда можно пароли руками вводить"), тогда как другие будут отстаивать удобство и красоту ("а давайте ещё добавим в новую модель смартфона элегантный отсек для наушников / щеточку для ногтей / алкотестер / микрофаллоимитатор и т.п") Между этими крайностями всегда найдутся аргументы у каждой стороны. И нет, принципиальной разницы между естественными языками и ЯП я не вижу. И те и другие суть системы знаков.
Зачем же ограничивать гибкость типов аргументов? В некоторых случаях использование имени параметра вместо его позиции будет бесполезным и неуместным. Ограничение так же позволит избежать проблем, если вы планируете изменить имена позиционных аргументов в будущем.
Некоторые ф-ции из стандартной библиотеки имеют такую сигнатуру, например bool.
Changed in version 3.7: x is now a positional-only parameter.
Что выглядит вполне логичным, действительно, какие имя дать этому параметру? `o`, `x`, `a`?
И вполне логично запретить вызов
bool(a=x)
Ну, это же чушь? Повторюсь, а если я **kwargs передаю через цепочку вызовов? То мне делать дополнительные конвертации?
bool(a=x)
а это пускай просто проверяет единственный аргумент на то True или False. Если передали больше одного аргумента — ошибка выполнения.
Ну, это же чушь? Повторюсь, а если я **kwargs передаю через цепочку вызовов? То мне делать дополнительные конвертации?
Ну если вам не надо, то никому не надо, это очевидно.
а это пускай просто проверяет единственный аргумент на то True или False. Если передали больше одного аргумента — ошибка выполнения.
Там более весёлый механизм.
И вы не перепутали тело ф-ции и сигнатуру?
a = 6
# Код ниже присваивает b значение a ** 2
# и проверяет, если b > 0
if (b := a ** 2) > 0:
print(f'Квадрат {a} это {b}.') # Квадрат 6 это 36.
Тут либо условие, либо print неправильные.
Можно примеры таких библиотек? Если библиотека поддерживает 3.5/3.6 и особенно 3.7, то и 3.8 она будет поддерживать в большинстве случаев. 3.8 же ничего не ломает. В каких-то редких случаях, когда что-то сломалось, завязанное на низкий уровень, байткод, CPython API/Cython и т.п., обычно чинится авторами достаточно оперативно.
А библиотеками, которые до сих пор не поддерживают Python 3, не уверен, что вообще нужно пользоваться. Сейчас многие библиотеки в новых версиях уже 3.5 перестают поддерживать, потому что современный Python, если можно так выразиться, начинается с версии 3.6, какой смысл держаться за 2-ветку?
Мне вообще нравится, что сообщество раскачалось и перестало цепляться за старьё. Ну и кардинально ломать что-то в питоне перестали. В 3.6 устоялись аннотации и появились f-strings, в 3.7 async/await стали ключевыми словами (у некоторых это вызвало боль, например, Celery, TensorFlow), но с тех времен уже всё устаканилось и починилось.
Новые фичи Python 3.8 и самое время перейти с Python 2