netch80: (Default)
netch80 ([personal profile] netch80) wrote2012-07-04 02:16 pm

ещё питоновых грабелек

Кто с ходу увидит ошибку?

    for i in range(0,3):                                                    
        test.acct_servers[i].handleAcctRequest = \                          
                lambda p: handleAcctRequest(test, test.acct_servers[i], p)  

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

UPD[2012-07-05]: от gegmopo4:
... lambda p, i=i: (далее по тексту)
Работает, но я не берусь отправлять такое в общее репо.

[identity profile] blacklion.livejournal.com 2012-07-04 11:26 am (UTC)(link)
А там статические или динамические замыкания? :)

[identity profile] netch80.livejournal.com 2012-07-04 12:01 pm (UTC)(link)
А в чём разница?

[identity profile] blacklion.livejournal.com 2012-07-04 12:03 pm (UTC)(link)
Захватывается слепок энвайромента или сам энвайромент.
В первом случае всё должно работать правильно, во втором вообще не понятно что будет с i после ухода из скоупа цикла. Ну, то есть, язык с GC, ясно что будет — у всех оно получится 3.
ext_605364: geg MOPO4 (Default)

[identity profile] gegmopo4.livejournal.com 2012-07-04 12:58 pm (UTC)(link)
В Питоне нет «скоупа цикла». И у всех получится 2.

[identity profile] blacklion.livejournal.com 2012-07-04 01:00 pm (UTC)(link)
Почему два, когда цикл (0,3)? Или там математическая запись — не включая концов?

[identity profile] p1r4nh4.livejournal.com 2012-07-04 01:05 pm (UTC)(link)
А, там range(0, 3) - ну это то же самое фактически (0 - дефолтный там).

[identity profile] blacklion.livejournal.com 2012-07-04 01:29 pm (UTC)(link)
Очень интуитивно, ага. Я бы понял, если бы (0,3) было бы 1 и 2 (ну, в целых числах), в [0,3] — 0, 1, 2 и 3. А так — вообще бред. Это же range()! Почему у него один конец включён, а второй — нет?

[identity profile] p1r4nh4.livejournal.com 2012-07-04 01:31 pm (UTC)(link)
Потому что range(3) - это ряд из 3 элементов. А генерировать ряд, не включая 0 - неудобно жить будет. Поэтому [0, 1, 2].

Когда пишут фор в си-подобных языках, тоже пишут (i = 0; i < 10; i++), а не i <= 9. Всë ок, так удобно жить.

[identity profile] blacklion.livejournal.com 2012-07-04 01:32 pm (UTC)(link)
Я, кстати, по-разному пишу, зависит от реальных границ. Например, от 0 до 0x7f я напишу с равенством а не строгое неравенство до 0x80.
Не знаю, почему.

[identity profile] p1r4nh4.livejournal.com 2012-07-04 01:34 pm (UTC)(link)
Ну, я б сказал, что мне так было бы проще понять - всë-таки 16-ричная система счисления не настолько привычна, как 10-ричная, с ней меньше общаешься в жизни.
ext_605364: geg MOPO4 (Default)

[identity profile] gegmopo4.livejournal.com 2012-07-04 01:50 pm (UTC)(link)
Удобно, если элементы массива нумеровать с 1.

[identity profile] p1r4nh4.livejournal.com 2012-07-04 01:52 pm (UTC)(link)
Это вызывает кучу других неудобств. Я с Луа уже достаточно повозился, чтоб меня это начало раздражать. :)

[identity profile] p1r4nh4.livejournal.com 2012-07-04 02:23 pm (UTC)(link)
Хотя бы потому, что ломается то, о чëм рассказывал Дейкстра: http://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html

Если мы начинаем с 0, то индекс меньше длины. А если с 1, то меньше или равен - и начинают вылезать ошибки на 1 в разных местах. :(

Я когда-то видел статью, написанную внятнее, чем у Дейкстры, но в целом сначала думаешь "а что, прикольно", а потом все эти ошибки на 1 когда вылезут - становится совсем невесело.

Это надо сказать, что в Луа с ними проще, чем там в жс или в си - есть итераторы типа pairs/ipairs, которые вернут что надо, иначе бы циклы довольно стрëмно выглядели.
ext_605364: geg MOPO4 (Default)

[identity profile] gegmopo4.livejournal.com 2012-07-05 08:27 am (UTC)(link)
Не пойму, что там у Дейкстры ломается, кроме привычки.

[identity profile] dottedmag.livejournal.com 2012-07-04 07:28 pm (UTC)(link)
Потому что операции над открытыми и закрытыми интервалами гораздо сложнее, чем над полуоткрытыми:

[a,a) ==> empty
[a,b) [b,c) ==> [a,c)
[a,b) [c, d) ==> [b, c)
(следствие) [a,b) [b,c) ==> empty
(следствие) a <= b <= c ==> [a,c) = [a, b) [b, c), при этом <= в левой части существенно.

С открытыми и закрытыми появляются граничные случаи в количествах.

[identity profile] dottedmag.livejournal.com 2012-07-04 07:30 pm (UTC)(link)
Жыжы съел тэги.

[a,b) union [b,c) => [a,c)
[a,b) intersect [c,d) => [b,c)
[a,b) intersect [b,c) => empty
a <= b <= c ==> [a, c) = [a,b) union [b,c)

[identity profile] p1r4nh4.livejournal.com 2012-07-04 01:13 pm (UTC)(link)
Да, кстати, в новом джаваскрипте (harmony) ввели блочный скоупинг (let вместо var), и там при таких раскладах всë будет хорошо:

let lambas = [];
for (let i = 0; i < 10; i++) {
lambdas.push(function() { console.log(i); });
}

Это будет работать как хочется.

[identity profile] p1r4nh4.livejournal.com 2012-07-04 12:28 pm (UTC)(link)
А где статические? Хаскель, окамл, кто-то еще?

[identity profile] blacklion.livejournal.com 2012-07-04 12:29 pm (UTC)(link)
Некоторые лиспы, как я понимаю. Но далеко не все.

[identity profile] p1r4nh4.livejournal.com 2012-07-04 12:42 pm (UTC)(link)
В елиспе вообще кошмар - не просто лениво, а архилениво: `i` должна быть забинжена в текущем скоупе, а иначе только через параметризацию и новое замыкание. В коммон лиспе емнип такая же лажа, но лень ставить, чувак напротив говорит, что в схеме вроде бы тоже так.

В кложуре всë immutable, там просто иначе никак не выйдет, так что там нормально. Итого - хаскель, окамл, кложура. Хз, что там в ерланге.

[identity profile] lionet.livejournal.com 2012-07-04 06:03 pm (UTC)(link)
Эрланг как хаскель в этом отношении.

[identity profile] w00dy.livejournal.com 2012-07-04 11:50 am (UTC)(link)
я так понимаю в использовании i внутри лямбды и последующем ленивом вычислении данного выражения.

[identity profile] netch80.livejournal.com 2012-07-04 12:01 pm (UTC)(link)
Именно. Но в таком виде оно вначале не ожидается:(

[identity profile] p1r4nh4.livejournal.com 2012-07-04 12:27 pm (UTC)(link)
Оно нигде так не ожидается и в большом количестве языков так работает - питон, руби, луа, го, кого я там еще забыл. Раздражает, конечно.
ext_605364: geg MOPO4 (Default)

[identity profile] gegmopo4.livejournal.com 2012-07-04 01:02 pm (UTC)(link)
Это причина, почему в Java в анонимных классах доступны только финализированные внешние переменные и почему в C++11 у лямбд такой относительно громоздкий синтаксис.
ext_605364: geg MOPO4 (Default)

[identity profile] gegmopo4.livejournal.com 2012-07-04 12:53 pm (UTC)(link)
lambda p, i=i:

[identity profile] netch80.livejournal.com 2012-07-05 06:15 am (UTC)(link)
Ты аццкая сотона! :) Работает, хотя я не решусь выставить такой код на обозрение других.
Так что сделаем другим путём.

[identity profile] p1r4nh4.livejournal.com 2012-07-05 07:38 am (UTC)(link)
Почему? Для питона это нормальный путь, забиндить переменную локальную через дефолтные аргументы.

[identity profile] netch80.livejournal.com 2012-07-07 06:24 am (UTC)(link)
Мне ж ещё с другими людьми работать над этим кодом, они хуже понимают такие идиомы.
ext_605364: geg MOPO4 (Default)

[identity profile] gegmopo4.livejournal.com 2012-07-05 08:25 am (UTC)(link)
Это идиома. А во времена, когда из лямбды внешние локальные переменные не были видны, это был единственный способ.

А что за другой путь? Чем он отличается?

[identity profile] netch80.livejournal.com 2012-07-06 05:21 am (UTC)(link)
Создали виртуальный метод для переопределения и свой подкласс для нужных целей.

[identity profile] netch80.livejournal.com 2012-07-07 06:25 am (UTC)(link)
Знаю. Это отрицательная сторона коллективной работы - необходимость унификации стиля и адаптации под способности всех.
ext_605364: geg MOPO4 (Default)

[identity profile] gegmopo4.livejournal.com 2012-07-07 06:54 am (UTC)(link)
List comprehensions у вас тоже забанены? Если range(0,3) не описка, я начинаю думать плохое.

[identity profile] netch80.livejournal.com 2012-07-07 10:44 am (UTC)(link)
Нет, не забанены.
Не описка.
Что именно плохое?
ext_605364: geg MOPO4 (Default)

[identity profile] gegmopo4.livejournal.com 2012-07-07 05:51 pm (UTC)(link)
Ну, по какой причине может появится range(0,3) вместо нормального range(3)? Первое, что приходит в голову (и наиболее вероятное) — опечатка или артефакт редактирования. Возможен ещё вариант разумного использования, если тут же рядом в коде есть range(1,4), range(2,5), range(-1,2) и т. п., причём в широком ассортименте. Но это очень, очень редкий случай. Остаётся ещё способности и вкусы кого-то, обладающего властью (чтобы принудить к этому питонистов), — т. е. просто самодурство.

[identity profile] netch80.livejournal.com 2012-07-08 06:53 am (UTC)(link)
range(0,3) появляется очень просто: я его написал потому, что я запомнил вариант использования как range(min,limit) и не желаю специально думать о его редукции до range(3) в тех условиях, когда я хотел сказать именно "от 0 до 2 включительно". Это при том, что если мне стоит задача "повторить 10 раз", я напишу range(10), а не range(0,10). Это пример на полезные шаблоны (или даже паттерны) мышления, которые позволяют не влезать в лишние детали.

То, что Вы не рассматриваете такую причину в принципе, а вместо этого придумываете какое-то "самодурство", говорит, что Вы не используете полезную экономию мышления. И это грустно.
ext_605364: geg MOPO4 (Default)

[identity profile] gegmopo4.livejournal.com 2012-07-08 07:45 am (UTC)(link)
Похоже, что я обидел лично вас. Жаль.

[identity profile] netch80.livejournal.com 2012-07-10 06:48 pm (UTC)(link)
Да, есть немножко. Но "жаль" должно быть не по поводу обиды лично меня или кого-то ещё, а по поводу скоропалительных обобщений и выводов из них.

[identity profile] migmit.livejournal.com 2012-07-05 06:26 am (UTC)(link)
Нормально.
> var a = []; for (i = 0; i < 3; i++) {a[i] = function() {console.log(i);}}; a[0]()
3