1. xcat

    25.12.2009

    0 ↑
    0 ↓
    Случайно столкнулся и пропарился пару часов.
    Сказывается изучение питона с помощью гугления :(

    Мне казалось что в питоне все ссылки, поэтому был написан такой код:
    def convert_row( row ):
    for attr in row:
    if isinstance( attr, str ):
    attr = unicode( attr, 'cp1251' )
    elif isinstance( attr, Property):
    attr = str(attr)
    который все отрабатывал правильно, но поля на выходе в row не изменялись.
    В результате такой код работает, но он мне не нравится:
    def convert_row( row ):
    for i in range(0,len(row)):
    if isinstance( row[i], str ):
    row[i] = unicode( row[i], 'cp1251' )
    elif isinstance( row[i], Property):
    row[i] = str(row[i])
    Подскажите какую основополагающую вешь я не понимаю?

    UPDATE:
    Код правил, но так и не понял как сделать чтобы квадратные скобки отображались в коде.
  2. Ferroman

    25.12.2009

    0 ↑
    1 ↓
    А что есть 'row'?
    Почему нельзя явно вернуть результат из функции?
    Ну и если row - список, то первый вариант кода тоже бы заработал.
  3. Иван Сагалаев

    25.12.2009

    1 ↑
    0 ↓
    def convert_row( row ):
        for attr in row:
            if isinstance( attr, str ):
                attr = unicode( attr, 'cp1251' )
    

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

    Обходится это двумя способами.

    1. Примерно так, как у вас во втором примере, явно перезаписывая row[i]:

      def convert_row(row):
         for i, attr in enumerate(row):
             if isinstance(attr, str):
                row[i] = unicode(attr, 'cp1251')
             elif isinstance(attr, Property):
                row[i] = str(attr)
      

      Но этот подход совсем не питоний, никто не меняет списки прямо по месту.

    2. Лучше просто создать новый список на основе старого, сделав функцию, которая работает не над списком, а над отдельным атрибутом. По сути это классический "map".

      def convert_attr(attr):
          if isinstance(attr, str):
              return unicode(attr, 'cp1251')
          elif isinstance(attr, Property):
              return str(attr)
      
      row = [convert_attr(attr) for attr in row]
      
      # или то же ещё короче:
      row = map(convert_attr, row)
      

    К слову, в этом коде и других непитонизмов достаточно. Использование isinstance всегда подозрительно, стоит посмотреть, нельзя ли всё отрефакторить так, чтобы объекты использовались как есть. Также, после такого преобразования у вас получится список с разными типами объектов (unicode и str), что тоже не очень красиво.

  4. xcat

    25.12.2009

    0 ↑
    0 ↓
    Спасибо Иван.
    К сожалению с помощью питона пытаюсь привести в REST старую CORBA систему.
    Или к счастью.

    Начал я действительно с map.

    А закончил таким непитонизмом. Row это действительно список содержащий объекты разных типов. Для примера строка БД. Эту типизацию хочется сохранить. Но строки хочется отдавать в юникоде, а не в 1251 как они приходят из корбы.

    Конвертить по индексу, только конкретные атрибуты не получается тоже, потому что заранее неизвестен порядок запроса. А копировать весь результат не позволяет бережное отношение к памяти :))

    Есть идеи? Хотя даже пример с enumerate меня почти примиряет с жизнью
  5. xcat

    25.12.2009

    0 ↑
    0 ↓
    Переделал обратно на map
    получилось читабельнее. Пока это важнее памяти.
  6. Иван Сагалаев

    25.12.2009

    2 ↑
    0 ↓

    За память вы совсем зря беспокоитесь. Garbage collection вполне себе хорошо работает. Я бы даже сказал, что на Питоне невозможно эффективно писать, если думать о таких вещах. Это же не Си.

Внимание! Это довольно старый топик, посты в него не попадут в новые, и их никто не увидит. Пишите пост, если хотите просто дополнить топик, а чтобы задать новый вопрос — начните новый.