LINUX.ORG.RU
ФорумTalks

Плохой Питон

 ,


0

5

по мотивам предыдущего треда.

Вот имеется функция.

def foo(bla):
   if bla > 10 and bla < 20:
        raise ValueError('Некорректно bla: какая-то херь!')

По данному коду:

  1. мы железно знаем что ошибку допустил код вызывающий нас
  2. поэтому правильно бросать исключение указывающее на строку нас вызывающую, а не на нас
  3. как бросить такое исключение?

хочу как в человеческом языке оператор

croak

PS: так же крайне удручает отсутствие полноценных лямбда-функций в этом говноязыке. Блин, как вы живёте без лямбд-то? только не надо мне тыкать в лямбда-оператор, я функцию хочу!

★★

как бросить такое исключение?

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

только не надо мне тыкать в лямбда-оператор, я функцию хочу!

Ты хочешь придраться к чему почучится, учитывая твои скудные знания языка. Есть lambda, есть вложенные def, как положено с лексическим замыканием, что ещё нужно?

slovazap ★★★★★ ()
Ответ на: комментарий от slovazap

Если оно провалится наверх, у тебя будет полный трейс всего

мне не нужен трейс указывающий туда, где ошибки нет!

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

rsync ★★ ()

поэтому правильно бросать исключение указывающее на строку нас вызывающую, а не на нас

Не надо стрелять в ногу.

i-rinat ★★★★★ ()
Ответ на: комментарий от slovazap

Есть lambda, есть вложенные

лямбды нет.

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

rsync ★★ ()
Ответ на: комментарий от i-rinat

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

я хочу как раз в ногу не стрелять, а сразу указать на проблемное место

rsync ★★ ()
Ответ на: комментарий от rsync
% cat 1.pl
use Carp;
  
sub test {
    my ($a) = @_;

    if ($a > 10 && $a < 20) {
        croak "TEST";
    }
}

test(15);
% perl 1.pl
TEST at 1.pl line 6.
	main::test(15) called at 1.pl line 11
% cat 1.py
def foo(a):
    if a > 10 and a < 20:
        raise ValueError('TEST')

foo(15)
% python 1.py
Traceback (most recent call last):
  File "1.py", line 5, in <module>
    foo(15)
  File "1.py", line 3, in foo
    raise ValueError('TEST')
ValueError: TEST

Подумай как следует где более информативное сообщение об ошибке. А вообще с трейсом ты можешь сделать что угодно.

slovazap ★★★★★ ()
Ответ на: комментарий от rsync

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

Как ты себе это представляешь? Цепочка вызовов может быть достаточно длинной, а неправильные данные вовсе необзятельно возникли именно на предыдущем вызове.

хочу как в человеческом языке оператор croak

Perl - это идиотский язык и наличие оператора croak - лишнее тому подтверждение.

bbk123 ★★★★★ ()
Ответ на: комментарий от rsync

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

я хочу как раз в ногу не стрелять, а сразу указать на проблемное место

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

slovazap ★★★★★ ()
Ответ на: комментарий от slovazap

А вообще с трейсом ты можешь сделать что угодно.

мне не нужен трейс!

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

я хочу как в нормальных языках бросать информативные ексепшены, а не чтобы юзер разгребал сумасшедшей глубины трейсы и искал по ним информацию на тему «что он сделал не так»

rsync ★★ ()
Ответ на: комментарий от slovazap

потому что тебе нужно знать откуда ты вызвал функцию, всю цепочку

мне не нужно знать что из функции main вызвался код asyncio из него вызвался asynchttp из него asyncpg из него еще пять вариантов из него bar и в bar ошибка и из bar вызвался foo который бросил ексепшен.

я заранее знаю что ошибка в bar.

как убрать мусорный стектрейс?

rsync ★★ ()
Ответ на: комментарий от rsync

написать лямбду на три строки невозможно

Ты ж неуч и врушка :))

map(
    lambda x:
        x
        +
        x
        *
        x
    , [1, 2, 3]
)

обязательно нужно геморроиться с временными переменными (именами функции)

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

slovazap ★★★★★ ()
Ответ на: комментарий от bbk123

Perl - это идиотский язык и наличие оператора croak - лишнее тому подтверждение.

если Python такой неидиотский язык, то как пользователю библиотеки указать на его ошибку.

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

rsync ★★ ()

Выдавай просто более информативное сообщение об ошибке, наподобие:

имя_функции: аргумент имя_аргумента: значение некорректно потому что гладиолус
что с ним делать, программист, имеющий на руках полный стектрейс, разберётся

eternal_sorrow ★★★★★ ()
Последнее исправление: eternal_sorrow (всего исправлений: 1)
Ответ на: комментарий от rsync

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

Ты никогда не отлаживал код, не искал ошибки по трейсам, так зачем ты какие-то хотелки придумываешь? Ещё раз: вызывающего кода может быть много, и прийти к нему можно разными путями. Чтобы понять как была вызвана твоя всезнающая функция обязателен полный трейс. Я повторяю, обязателен, независимо от твоих желаний. Осознай это.

я хочу как в нормальных языках бросать информативные ексепшены

Python умеет всё что умеют другие языки и даже больше. Если нужно показать ошибку юзеру - поймай исключение где удобно и выведи ошибку. Как в любом другом языке. В отличие от многих языков где этого нет, ты можешь инспектировать всю цепочку вызовов и вывести всё что тебе вздумается. Можешь только непосредственную точку вызова твоей функции, можешь третью с конца, можешь в обратном порядке справа налево.

slovazap ★★★★★ ()
Ответ на: комментарий от rsync

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

bbk123 ★★★★★ ()
Ответ на: комментарий от slovazap

Ты ж неуч и врушка :))

я говорил про лямбда-функцию на три строки, а не оператор в ней на три строки.

напиши в ней цикл for или пару операторов if-else

rsync ★★ ()
Ответ на: комментарий от rsync

напиши в ней цикл for или пару операторов if-else

Так на то и есть функции высшего порядка и flow control выражениями.

vvn_black ★★★★★ ()
Ответ на: комментарий от hc

то всё, пропали ассерты

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

vvn_black ★★★★★ ()

поэтому правильно бросать исключение указывающее на строку нас вызывающую, а не на нас

А че так негибко, давай сразу оператор blame. С двумя вариантами аргумента, либо файл + строка, либо сразу емэйл виновного. А без параметров пусть подставляется Поттеринг.

t184256 ★★★★★ ()
Последнее исправление: t184256 (всего исправлений: 1)
Ответ на: комментарий от vvn_black

Ассерты вообще не для этого, а при генерации pyo они в принципе выпиливаются.

WitcherGeralt ★★ ()
Ответ на: комментарий от slovazap

А ты — тролль. Мог бы ещё строк 7 из этого кода выжать. Была бы совсем «многострочная» лямбда.

WitcherGeralt ★★ ()
Последнее исправление: WitcherGeralt (всего исправлений: 1)
Ответ на: комментарий от bbk123

Perl - это идиотский язык и наличие оператора croak - лишнее тому подтверждение.

Perl - мёртвый язык, как и bash. И как ни странно, в некоторых областях это огромное достоинство. Код на перле без проблем работает на всём зоопарке ОС. Тогда как с python нужно специально заморачиваться с совместимостью используемого синтаксиса и модулей ( 2.6, 2.7, 3.x - выбирай любые 2, третий пойдёт лесом в подарок :\ )

Хотя сложные вещи на питоне написать проще и приятнее, это да :)

router ★★★★★ ()
Ответ на: комментарий от slovazap

Тут я с ТС согласен. В python какие-то искусственные ограничения на лямбды, там даже не все операции разрешены. С непривычки выносит мозг

router ★★★★★ ()
Ответ на: комментарий от slovazap

Python умеет всё что умеют другие языки и даже больше.

Так начинают питонисты спор.

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

а так заканчивают.

Deleted ()
Ответ на: комментарий от router

Единственное ограничение — одно вычисляемое выражение. Иногда хочется и многострочную лямбду, но та, что есть, очень нужна именно в таком виде. Питоническая лямбла идеально сочетается со словарями.

WitcherGeralt ★★ ()
Ответ на: комментарий от WitcherGeralt

а если б позволяла больше выражений, не только одно, то всё.

Deleted ()
Ответ на: комментарий от WitcherGeralt

Питоническая лямбла идеально сочетается со словарями.

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

router ★★★★★ ()
Ответ на: комментарий от WitcherGeralt

Но по-правде, то, о чём я говорил нафиг бы не впёрлось, если бы в питоне был switch.

WitcherGeralt ★★ ()
Ответ на: комментарий от router

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

3.5+

>>> from functools import reduce
>>> reduce(lambda x, y: {**x, **{y: y}}, range(5), {})
{0: 0, 1: 1, 2: 2, 3: 3, 4: 4}
>>>

vvn_black ★★★★★ ()
Ответ на: комментарий от vvn_black

Иногда словари со значениями в виде лямбд могут заменять switch, с перебором в цикле могут быть даже лучше него, а порой просто нужна компактная декларация каких-то преобразований или проверок, очень удобно.

WitcherGeralt ★★ ()
Последнее исправление: WitcherGeralt (всего исправлений: 1)
Ответ на: комментарий от vvn_black

3.* не нужен и не считается. Нечитаемое говно же. Был нормальный язык, взяли и всё всрали.

WitcherGeralt ★★ ()
Последнее исправление: WitcherGeralt (всего исправлений: 1)
Ответ на: комментарий от WitcherGeralt

словари со значениями в виде лямбд могут заменять switch

Свитч и if...elif..else.. хорошо заменяют ленивые вычисления, выглядят не хуже и после пары конструкций привыкаешь.

vvn_black ★★★★★ ()
Ответ на: комментарий от vvn_black

Это неплохо, я считаю, тут и многострочная лямбда и замена свитчу:

bat_icon = lambda x: x <= 15 and '\uf244' or \
                     x <= 37 and '\uf243' or \
                     x <= 62 and '\uf242' or \
                     x <= 85 and '\uf241' or '\uf240'
bat_icon(45)  # иконка 50% батарейки

vvn_black ★★★★★ ()
Ответ на: комментарий от vvn_black

Специально до компа добрался, чтобы показать тебе, как это и на православном втором питоне без проблем делается без вейпов и смузей, причём на той же скорости даже без оптимизаций:

In [1]: from functools import reduce

In [2]: %timeit reduce(lambda x, y: x.update({y: y}) or x, range(5), {})
1000000 loops, best of 3: 1.19 µs per loop

In [1]: %timeit reduce(lambda x, y: {**x, **{y: y}}, range(5), {})
The slowest run took 12.69 times longer than the fastest. This could mean that an intermediate result is being cached.
1000000 loops, best of 3: 1.11 µs per loop

WitcherGeralt ★★ ()
Последнее исправление: WitcherGeralt (всего исправлений: 1)
Ответ на: комментарий от vvn_black

Либо:

switch, default = {
    '\uf244': lambda x: x <= 15,
    '\uf243': lambda x: x <= 37,
    '\uf242': lambda x: x <= 62,
    '\uf241': lambda x: x <= 85
}, '\uf240'

for val, case in switch.items():
    if case(x):
        break
else:
    val = default

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

Один раз мне понадобился крошечный DSL, сделал как раз на словаре как раз с помощью лямбд.

WitcherGeralt ★★ ()
Ответ на: комментарий от i-rinat

Хмм.. А ТС прав. Если исключение бросает «наш» код, то ловить это исключение должен вышестоящий, вызывающий. И даже если он имел ввиду бросание исключения в вышестоящем (т.е. превалидация), тоже себе нормальное решение.

deep-purple ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.