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

    −105

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    def read(self):
            self._skip_whitespace()
            ch = self._peek()
            if ch in ',:[]{}':
                return self._read(), None
            elif ch == 'n':
                return self._read_literal('null'), None
            elif ch == 't':
                return self._read_literal('true'), True
            elif ch == 'f':
                return self._read_literal('false'), False
            elif ch == '"':
                return self._read_string()
            elif ch in '-0123456789':
                return self._read_number()
            else:
                raise UnexpectedCharacter(ch)

    Просто взять и уебать таких писателей. httpstream/jsonstream.py

    Запостил: wvxvw, 03 Октября 2013

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

    • def _read_number(self):
              pos = self.data.tell()
              src = []
              has_fractional_part = False
              try:
                  # check for sign
                  ch = self._peek()
                  if ch == '-':
                      src.append(self._read())
                  # read integer part
                  ch = self._read_digit()
                  src.append(ch)
                  if ch != '0':
                      while True:
                          try:
                              src.append(self._read_digit())
                          except (UnexpectedCharacter, EndOfStream):
                              break
                  try:
                      ch = self._peek()
                  except EndOfStream:
                      pass
                  # read fractional part
                  if ch == '.':
                      has_fractional_part = True
                      src.append(self._read())
                      while True:
                          try:
                              src.append(self._read_digit())
                          except (UnexpectedCharacter, EndOfStream):
                              break
              except AwaitingData:
                  # number potentially incomplete: need to wait for
                  # further data or end of stream
                  self.data.seek(pos)
                  raise AwaitingData()
              src = "".join(src)
              if has_fractional_part:
                  return src, float(src)
              else:
                  return src, int(src)


      Ох, блять, это еще не все, как оказалось. Все из того же замечательного файла
      Ответить
      • а че какого bison/flex для питона нету? задача же тривиальная...
        Ответить
        • Есть штуки три-четыре, на разные вкусы, но тут люди героически решили сделать что-то абсолютно запредельно ненужное.
          Обычный парсер генератор создаст какой-нибудь LL(1), или, если нельзя, то LR(1), или можно попробовать PEG (packman parser) - все с хорошо известной асимптотикой и т.д.
          Но тут дело в том, что захотелось парсить не все сразу, а с остановками, на манер как SAX может парсить XML. И в этом есть определенный смысл, начиная примерно с мультимегабайтных файлов.
          Но в пределах этой библиотеки бультимегабайтные файлы не ожидаются, т.как парсится HTTP ответ от базы данных. Если он будет таких запредельных размеров, то пользоваться этим будет не возможно, даже если памяти на это много и не потребуется. Пользователь на другом конце не станет ждать часами ответа.
          Ответить
          • > Но тут дело в том, что захотелось парсить не все сразу, а с остановками

            ок. тогда без bison/flex. что делает парсинг json из тривиального простым. как раз случай для fsm. и если делать в нативном питоне, то итеративность можно реализовать yield'ами. (я корутинами не пользовался, я такое только через коллбэки реализовывал.)
            Ответить
          • блин, граматика даже на главной странице отображена: http://www.json.org/ ....
            Ответить
            • Да, а как я это обнаружил. Написал запрос. Когда запрос небольшой, то все работает, чуть только доходит до ~50К, код валится с непонятной ошибкой "неожиданый символ Е". Естесственно, в теле ответа символов "Е" несколько сотен, а замечательный парсер не сообщает позицию, где случилась ошибка.
              Естесственно, я в первую очередь себя проверял, искал может я что-то не так записал изначально, может быть "Е" - это на самом деле какой-то другой символ, который так странно отобразился и т.д.

              Вообще так испахабить идею... это я как бы пытаюсь научиться работать с графовыми базами данных. И, ну просто диву даешся какие идиотские идеи люди приделывают к, вобщем, замечательному основанию. Посмотреть на тот же Сайфер / Гремлина - это ж просто пиздец. Язык который умеет так мало, и при это в нем столько сущностей... Безумная какая-то грамматика, к которой документ был написан каким-то филателистом любителем.
              И нормального интерфейса к базе данных нет, т.как сама база написана на Яве, и создатели, естесственно, постарались энтерпрайз налепить. Как встроенную, ее еще можно использовать - но это значит, писать на Яве, т.как ее больше никуда не встроишь. А использовать ее из чего-то другого - пайплайн становится таким невероятно тормозным, что херит на корню все плюшки вобщем-то принципиально очень быстрой бд.

              teh drama
              Ответить
              • > постарались энтерпрайз налепить
                > teh drama

                есть такие как мы, которые это говном называют.

                а есть продвинутые которые клиентам под это дело консалтинг продают и еще больше энтерпрайза лепят - и бабло большое за это имеют.
                Ответить
    • Аа что? Парсеры, они такие. Да и тормозить все это на питоне будет. json парсер искаропки частично сишный.
      Ответить
      • Не парсит флоаты вида 1.234е56. Но это не главное, главоное - какого хуя они его вообще написали, почему не воспользовались существующим?
        Ответить
        • > почему не воспользовались существующим
          А что, есть стандартный потоковый pull-парсер? Вижу json.iterencode, iterdecode не наблюдаю.
          Ответить
          • У стандатронго есть колбеки, которые можно было использовать в строительстве, если так сильно хотелось. Это говно как бы ни парсило, все равно будет очень медленным. Лучше уже распарсить весь сишным, но быстро, чем ждать это, но по часттм.
            Ответить
            • Парсер с callback это push, а не pull парсер. Парсер, предоставляющий поток событий (вроде StAX или Jackson для жабы), на практике гораздо удобней.
              http://govnokod.ru/13873#comment198065
              Задумку авторов того, что в посте, я, разумеется, не одобряю и не оправдываю.
              Ответить
              • Тут еще такой момент, что все эти ухищрения с постепенным парсингом обламываются об то, что структура иерархическая: ну и что что я смогу распаристь часть, и мне тут же понадобиться узнать сколько дочерних элементов есть у элемента на вершушке иерархии? Если бы это было чем-то вроде таблицы - еще можно понять, а так - бессмысленное извращение.
                Ответить
                • Сильно зависит от задачи. В большинстве случаев весь контекст знать не нужно. Если мы просто преобразуем список небольших объектов в другой формат, то нам редко нужно знать весь контекст.
                  Появилось свойство на входе - преобразовали и записали в выход. Если нужно что-то аккумулировать, аккумуляторы выводим последними.
                  Это даёт возможность обрабатывать большие массивы данных небольшими ресурсами и относительно простым кодом.
                  К примеру, есть xml-ки в 10Гб и json-файлы аналогичного размера, которые надо конвертировать / заливать в базу. На таких масштабах наивные подходы не работают.

                  В любом случае, имея pull-парсер, легко построить push-парсер и вообще реализовать любое удобное апи.
                  Ответить
                  • > наивные подходы не работают
                    Покупаем больше памяти, и 10 гиг в нее входят ;)
                    Ответить
                    • Проблема в том, что dom-представление xml-файла, полученное из libxml2, занимает места в несколько раз больше, чем сам файл. Пробовали распарсить в dom - отожрало на сервере 90Gb оперативки :)
                      Ответить
                      • > 90Gb оперативки
                        Нищебродский сервак. Всего 90 гигов. Само собой этого не хватит...
                        Ответить
                      • у нас на проекте нечто подобное. но только с sax, потому что все равно контент перед заливом в базу надо дополнительно обработать.

                        я конечно повторяюсь, но если у вас 10Гб файлы, но выбор xml как формата файла был очевидно ошибочным. с json я догадываюсь те же яйца. форматы для структурированых данных очень плохо подходят для представления структурированного потока данных.
                        Ответить
                      • Как так? Ключи разве не повторяются? Или 10 гиг - это сжатый был?
                        Ответить
                        • > Ключи разве не повторяются?
                          Ключи повторяются, но вот либа, похоже, не утруждает себя их интернированием. Разбираться не стали, просто переписали.
                          Ответить
                          • Ах да, в питоне же сишный и питонистый код отдельно. Я чет подумал, что раз в питоне есть lxml, то там строки тоже интернируются. СИШКОПРОБЛЕМЫ.
                            Ответить
                  • Этра херня никогда не справится с задачами типа "залить в базу гигабайты данных". Оно работает через HTTP, и накладных расходов на посылку там очень много. 5млн записей за 3 часа: http://stackoverflow.com/questions/19014822 за это же время можно было написать на Яве импорт, начать импорт собственно и закончить.
                    Но мы говорим про парсер, т.е. про чтение а не про запись. В каком случае нам не нужно будет прочитать весь ответ от сервера? Зачем мы тогда этот запрос посылали вообще? Кроме того, по занимаемой памяти - вовсе не факт, что строка будет занимать меньше памяти, чем собраный объект (числа представленные строкой занимают больше памяти, ключи многих объектов будут почти наверняка повторяться).
                    Тут было уже упомянута разница между пуш / пул парсерами. Ну вот предположим мы действительно получили очень большой ответ и хотим его переправить по частям дальше по инстанции: опять же, нам ничто не поможет выбросить уже посланные объекты до того, как мы не прочитаем весь объект на верхушке иерархии. Т.е. ради мнимого удобства (а на самом деле просто очевидно потому, что очень хотелось сделать самому) получили и потерю производительности, и баги, и кучу других проблем.
                    Ответить
                    • Повторюсь
                      > Задумку авторов того, что в посте, я, разумеется, не одобряю и не оправдываю.
                      Ответить
                    • > В каком случае нам не нужно будет прочитать весь ответ от сервера?
                      XML'ки бывают не только в ответах от сервера. Например стартовая выгрузка того же ФИАС'а (реинкарнация КЛАДР'а) содержит 8 гиговую XML'ку.

                      Ваш кэп.
                      Ответить
                      • питонья либа типа для http стриминга
                        Ответить
                      • А ну да. Я мелковатый пример привел. XML'ка с полным дампом open street map весит на порядок больше :)
                        Ответить
                      • Кэп, это библиотека специально написана для того, чтобы парсить ответы от ниофорджа, это часть питунео (они вместо того, чтобы вынести ее во внешние зависимости, встроили ее целиком в свой пакет). У нее даже в теории не предполагается других вариантов использования.
                        Ответить
                • а AST не строится? по дереву разбора можно было бы вернуться, и передавать относительные оффсеты на продвижение парсера по входному файлу, так при падении, вернувшись в корень AST, можно узнать оффсет в во входном файле. Знаю, что деревянный способ - но дереву-деревово, а что тут еще сделать - ХЗ
                  Ответить
          • google:python json incremental parser пару костылей дал.
            Ответить

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