Pull to refresh

Comments 54

Когда ожидается введение begin/end?

UFO just landed and posted this here

Велик Питон, а отступать некуда! (с) Ну или почти так)

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

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

# сферический case в вакууме
import libvirt
if (conn := libvirt.open()) and (dom := conn.lookupByName('myhost')) and dom.isActive():
    dom.poweroff()

Ну классно же ж

Classic way:
```py

conn = libvirt.open():
if conn:
dom = conn.lookupByName('myhost'):
if dom:
active = dom.isActive()
if active:

dom.poweroff()

```

No comments

PS. дурацкий редактор в хабре, ппц

Почему у вас наступает эффект замедления чтения кода при виде моржового оператора?

Это очевидно даже из примеров в статье - усложнение кода одной строки.

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

  1. Усложнение кода одной строки

  2. Выражение мысли в двух строках

Для меня совершенно не очевидно, что прочитать две "простые" строки будет быстрее, чем одну "сложную".

Дзен питона: п.6 Разреженное лучше, чем плотное.

Две строки лучше чем одна. (хотя порой и хочется запихать в одну побольше :)

Это правда, что в Питоне более идиоматично будет написать в две строки, а не в одну. Это не является объективным добром, но в Питоне так принято. Что интересно, мне кажется, что на скорость чтения это может не влиять, если привыкнуть к моржовому оператору. Если привычно, то не будет ступора от непонятной конструкции.

Есть один нюанс.
Модуль должен быть читабелен. Из моей практики 200..250 строк оптимально. И это с учетом 2 строки между классами/функциями, 1 строка между методами, докстринги и прочие PEPs. Больше 500 строк модуль становится неуправляемым.
А впихнуть надо. Ибо класс.

Поэтому таки да таки не - не всегда разреженное лучше.

А впихнуть надо. Ибо класс.

В питоне нет partial?

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

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

Вы что, бородатые паскалисты оценят

Не только бородатые (у меня нет бороды), и не только пасквилянты. Есть такой язык ST в стандарте IEC 61131-3, по синтаксису просто гибрид между паскалем и си. Приходится регулярно на нём писать, плюс, когда-то на паскале писал тоже..

Поэтому, меня повеселило, что оператору даже имя специальное дали :)

Я как-то переводил на Хабре цикл статей Гвидо про реализацию нового парсера взамен ll(1). Вот там он моржа использовал очень часто. И код там получался с ним действительно лаконичнее без потери читаемости.

Интересно, в js такое поведение изначально с = и это считается очень плохим стилем, практически нигде кроме "хакерских однострочников" не вижу

Это не только в JS, это во многих языках, потому что унаследовано от C, в котором assignment is expression с самого начала. Но и C не был первым, в Algol 68 оно точно было, и даже в моржовом виде. Возможно, было в каких-то расширениях Fortran, не уверен. С большой натяжкой можно и Lisp упомянуть.

Можно отметить две вещи в C: возможность "опасного" присваивания внутри if (плохо) и возможность объявления, в нём нет места для ошибки (хорошо):

if (x = foo()) {...}      // точно ли нет ошибки? '=' или '=='?

if (int x = foo()) {...}  // точно нет

Из этих двух вещей в одних языках унаследовали только хорошую (D), в других - только плохую (JS).

и возможность объявления

Тьфу, это же только в C++ так. "A condition can either be an expression or a simple declaration."

https://en.cppreference.com/w/cpp/language/if

https://en.cppreference.com/w/c/language/if

Можно пойти дальше. Блок кода - тоже выражение, представляющее некую функцию. А там уже и вовсе перейти в Лямбда-исчисление Чёрча.

В условиях часто ошибаются, когда пишут = (присваивание) вместо == (сравнение):

if (x = 1) { /* всегда TRUE */}

if (x == 1) {}

Поэтому Гвидо в питоне с самого начала запретил использовать присваивание в подобных случаях.

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

Эти ошибочные условия ловятся всеми компиляторами уже лет 20 как.

Не все компиляторы, и не всегда ошибки. Например, на сях нет исключений, и на каждой строчке писать if ((res = f()) != ok) return res; намного лаконичнее, чем res = f(); if (res != ok) return res; в две строчки... Хотя я тоже не люблю такие конструкции...

На сях как раз и начали их ловить раньше всех. Выводится warning, а дальше уже сам.

Хоть и оператор не нашёл большого применения, но читать статьи о нём и его истории очень интересно!

Нужно быть готовым в скором будущем к такому коду
num := 7

print(num)

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

А так и нельзя писать

>>> a := 123
  File "<stdin>", line 1
    a := 123
      ^^
SyntaxError: invalid syntax

отлично! Получается что ввели целый оператор ради одного краевого случая. как по мне не лучшая это практика, плодить операторы.

y := f(x) # INVALID

(y := f(x)) # Valid, though not recommended

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

Самая жесть теперь когда скобки меняют семантику:

>>> f'{(x:=10)}' # Valid, uses assignment expression

'10'

>>> x = 10

>>> f'{x:=10}' # Valid, passes '=10' to formatter

' 10'

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

По идее, нужно было делать с самого начала как в первом варианте

Так не делают со времён Алгола-68, наверное. Потому что -:=,+:=,*:=,/:=,%:=...

Но была и другая возможность - переиспользовать as.

зато появился отличный вопрос валить джунов (а может и не только джунов) на собеседовании простым вопросом по операторам языка ;)

Куда проще завалить того, кто не понимает разницы между оператором и операцией.

Сказал человек, не знающий разницы между оператором и инструкцией /s

Удивительно, но собеседуемый ради денег может даже согласиться по чётным дням statement'ы называть операторами, по нечётным - инструкциями, сохраняя вид лихой и придурковатый и извиняясь за то, что он вчера он выбирал "неправильный" перевод термина.

>>> with open("./words.txt", "r") as file:
...     while line := file.readline().rstrip():
...             print(line)
... 
foo
bar
>>> with open("./words.txt", "r") as file:
...     for line in file.readlines():
...             print(line.rstrip())
... 
foo
bar

baz

В примере 2 (чтение строк из файла), реализация через моржовый оператор завершает чтение на первой пустой строке

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

Всё верно. К сожалению, автор решил показать "удобство" моржового оператора и, в то же время, отклонился от начальных условий к примерам. Такая же ситуация с примером 6 (All | Any)

Я использовал его разок, очень удобно в цикле, чтобы работал пока значение из функции не равно None

Впилили бы что то вроде using во включения, а то извращаться приходится

a = [foo: (bar,baz) for foo in arr if (bar:="qq", baz:="ww")]

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

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

Если под каждую алгоритмическую ситуацию придумывать новый оператор, то питон превратится в китайскую грамоту с тысячами иероглифов. Китайская грамота, кстати, очень лаконична, в одном иероглифе помещается несколько слов. Только учить и читать её замучаешься.

Перегрузка операторов не смущает?

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

В луа вообще ничего нет, даже индекс первого элемента в коллекции не 0, а 1...

Зачем нужна луа, если есть nodejs?

СлабО nodejs в микроконтроллер запихать?

А вот LUA легко.

Проблема этого кода заключается в том, что значение длины ключевого слова (len(word))
вычисляется дважды: один раз в условном операторе, второй — при выводе
текста. Решить проблему можно с помощью дополнительной переменной:

Насколько мне известно длина строки не высчитывается каждый раз. Она высчитывается один раз при создании. Так что пример несколько натянут

Тут автор скорее не точно выразил мысль таким упрощенным примером. "Проблема" тут в том, что дважды вызывается функция X (в примере это len, но вообще не важно), которая выполняет неизвестное количество вычислений.

И в общем случае, безусловно, лучше получить результат вычислений один раз, нежели дважды.

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

Странно говорить о том, что “позволяет” при прямо заданном контексте “отличие”. “Как использовать” — это не отличие.

Во-первых, присваивание = — это операция (operator), а не оператор (statement). Разница существенная, если вы задумываетесь о семантике.

Во-вторых, ключевое, принципиальное отличие = от := заключается в том, что операция (operator) := является выражением (expression), а всякое выражение имеет значение (value). Операция = выражением не является, и значения не имеет.

Таким образом, вы можете использовать := везде, где язык требует наличия значения. И это вовсе не деды от Pascal (который сам заимствовал := из Algol) себе на радость притащили в Python, это скорее “давайте ещё функциональщины в язык добавим.” Взгляните на Rust — там практически любой оператор является выражением. Удобно, чёрт побери, присвоить переменной значение цикла или условного оператора let x = if y {a} else {b};

В питоне и так можно было делать `x = 1 if my_condition else 2`.

А теперь мы получаем такие чудесные выражения (прям из описания pep)
`(x := 1, 2)` (x будет равен 1)
Так нельзя
`x := (1, 2, *[3, 4]`, но можно так `(x := (1, 2, *[3, 4]))` или так `(x := (1, 2, *[3, 4]), print())`
И все случаи, где оно могло бы пригодиться приходится заворачивать в скобки
`[b for a in range(10) if (b:= a**2) > 20]`
или
`[b for a in range(10) if (b:= a**2 > 20)]`
но не
[b for a in range(10) if b:= a**2 > 20]

Что мне всегда нравилось в Perl:
if (my $var = func()) {
...
}

теперь я знаю как в Python это делать =)

Sign up to leave a comment.

Articles