1. Python / Говнокод #14455

    −94

    1. 1
    2. 2
    3. 3
    4. 4
    5. 5
    6. 6
    def f(l = []):
            l.append(len(l))
            return l
    f()
    f()
    print f()

    Есть мнения что выведет?
    http://ideone.com/Q6Oc2I

    Запостил: laMer007, 31 Января 2014

    Комментарии (35) RSS

    • Тарас, а что сделает Ада?
      Ответить
    • Что именно тебя смущает? Это документированное поведение языка.
      Ответить
    • После веселой отладки пару недель назад, растянувшейся на пару часов сомнений больше нет.
      Ответить
    • Вот оно, удивление от языка.

      Ruby [0] выдает
      Ответить
    • Так всяко поинтереснее будет:
      x = ([], )
      print(x)
      try:
          x[0] += [42]
      except Exception as e:
          print("Caught", e)
      print(x)

      http://ideone.com/KTzQpn
      Ответить
      • а вот это реально круто
        Ответить
        • суть такова,
          x это тупл из листов, т.е. структура в которой лежат константные ссылки на не константные обьекты. При выполнении операции += для элемента тупла сначала вызывается оператор +
          для листа и соответственно в лист добавляется 42 затем вызывается оператор = а этот оператор уже пытается изменить адрес листа который константный => вуаля мы ловим ошибку. Как то так.
          Ответить
          • Вся загадочность в том, что кортеж оказывается измененным. Ошибка как-будто кинута пост фактум.
            Ответить
            • Кортеж остаётся таким же. Просто пытались присвоить ту же самую ссылку, что уже была.
              Ответить
            • Коментарий выше объясняет ситуацию. Кортеж не изменен изменен элемент а это не одно и тоже.
              Ответить
              • Хотя согласен это не правильная ситуация. Видимо разработчики старались сэкономить память и скорость.
                Ответить
          • >для элемента тупла сначала вызывается оператор +
            Нет, не так. += — это самостоятельный оператор, он не раскладывается на + и =. Только мб если __iadd__ вдруг не определен в каком-нибудь пользовательском классе. Но у list __iadd__ определенно есть.

            Там происходит что-то такое (то есть он раскладывается на '=' и __iadd__):
            x[0] = x[0].__iadd__([42])
            С поправкой на то, что x[0] вычисляется только один раз.
            Ответить
            • Про "вычисляется только один раз" я ерунду сказал.
              1           0 LOAD_NAME                0 (x)
                            3 LOAD_CONST               0 (0)
                            6 DUP_TOP_TWO
                            7 BINARY_SUBSCR
                            8 LOAD_CONST               1 (42)
                           11 BUILD_LIST               1
                           14 INPLACE_ADD
                           15 ROT_THREE
                           16 STORE_SUBSCR
                           17 LOAD_CONST               2 (None)
                           20 RETURN_VALUE

              Обращаю внимание на DUP_TOP_TWO: один раз пара (x, 0) используется для BINARY_SUBSCR (__getitem__), второй раз - для STORE_SUBSCR (__setitem__).
              Ответить
              • Ты прав.
                Ответить
                • Не может быть, этой фразе не место в интернете!!
                  Ответить
                  • хмм, если я скажу что ты прав произойдет ли деление на ноль?
                    Ответить
            • >x[0] = x[0].__iadd__([42])
              Если iadd меняет сам обьект, то зачем присваивание? И как ты дизассемблил код?
              Ответить
              • Да в общем-то незачем. Я думаю, транслятор просто не может заранее знать, какой тип стоит слева: есть ли у него изменяющий состояние __iadd__, или нет. У всяких чисел и строк __iadd__ нет, и INPLACE_ADD вызывает просто __add__.
                http://docs.python.org/3.3/library/dis.html
                Ответить
      • сначала присвоил, потом подумал)
        Ответить
      • сие заслуживает отдельного поста
        Ответить
    • Ахаха, все таки полезно читать мануал хотя бы уровня "для чайников".
      Ответить
    • WAT
      сразу вспомнилось.
      Ответить
    • Картина репина: Не ждали!
      Ответить
    • Классические баяны: Питон. ГК, 2014. Тираж 9999999 экземпляров.

      Дефолтовые значения аргументов функции вычисляются при компиляции, изменяемые объекты будут синглтонами. Конечно, большой вопрос - а нахуя так вообще сделали? Я бы назвал это багом.
      Ответить
    • http://rchan.cz/pr/src/1391494436037.jpg
      Ответить
    • Да это же double hit - раби и пейсон получили пруф некошерности.
      И как я пропустил такой великий тред Победы?!
      Ответить
      • Человек на радостях лямбдами упоролся, рухнул железный занавес и ему в мирок лямбды завезли, вот ему крышу и рвет.
        Ответить

    Добавить комментарий