Как стать автором
Обновить

Решил как-то абапер питон выучить. Часть 1

Так случилось, что довольно давно я работаю со "страшно дорогой 1С-кой немецкого происхождения"(с) по имени SAP, которая написана на ABAP.

Поэтому, можно сказать, что по долгу службы, для меня это основной язык.

Но как-то решил я выучить какой-нибудь еще язык для своих рутинных консовских задач (сверок/сводок и т.д.).

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

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

Дальше речь пойдет о частностях, поэтому коротко напишу, что задача (pet project) состоит в следующем: есть отчет для сдачи в госорганы в формате xml, есть проверочные данные в excel. Нужно выбрать файлы через GUI и их сравнить.

Если более общо, то задача состояла в том, чтобы научиться переводить с abap на python.

Для GUI был tkinter, для xml - xml.etree, для остального - pandas.

Ожидаемо, возник нюанс.

В ABAP для большинства задач, workhorse - это loop, read, sort внутренних таблиц по различным условиям.

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

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

Для понимания. Я пытался перевести на Python вот такой ABAP-код.

  TYPES: BEGIN OF ts_type,
           item   TYPE c LENGTH 10,
           number TYPE i,
           price  TYPE d,
         END OF ts_type,

         tt_type TYPE TABLE OF ts_type WITH EMPTY KEY.

  DATA(lt) = VALUE tt_type(  ( item = 'item1' number = 95 price = 100 )
                             ( item = 'item2' number = 85 price = 200 )
                             ( item = 'item3' number = 75 price = 300 )
                             ( item = 'item4' number = 65 price = 400 )
                             ( item = 'item5' number = 55 price = 500 )
                             ( item = 'item6' number = 45 price = 600 )
                             ( item = 'item7' number = 35 price = 700 )
                             ( item = 'item8' number = 25 price = 800 )
                             ( item = 'item9' number = 15 price = 900 )
                           ).

  LOOP AT lt ASSIGNING FIELD-SYMBOL(<fs>) WHERE item EQ 'item2' OR ( number GE 30 AND price LE 300 ).
    WRITE:/ <fs>-item.
    <fs>-price = 999.
  ENDLOOP.

Основное, конечно, это найти аналог вот этому:

  LOOP AT lt ASSIGNING FIELD-SYMBOL(<fs>) WHERE item EQ 'item2' OR ( number GE 30 AND price LE 300 ).
    WRITE:/ <fs>-item.
    <fs>-price = 999.
  ENDLOOP.

Для перевода куска выше (а он для меня был очень важен т.к. в моей голове, это workhorse для моих задач), я вышел в интернет(с). И почему-то не обнаружил искомого на поверхности. Может плохо искал. Собственно, поэтому и пишу этот пост.

Итого.

Дано: нужно пробежаться только по определенным строкам внутренней таблицы (без for ... if...), обращаться нужно по именам полей, содержимое таблицы нужно менять.

Больше всего хотелось оперировать именами полей. Ошень удобно...

  • namedtuple. Организация "таблицы" с полями "+", обращение по имени "+", поиск по условиям "-", изменение данных "-".

  • classdata. Либо я не понял, либо это аналог структуры(очень условно).

  • pandas dataframe. Вроде подошел.

import pandas as pd

df = pd.DataFrame(columns=['ITEM', 'NUMBER', 'PRICE'])

sample = [pd.Series(['item1', 95, 100], index=df.columns),
          pd.Series(['item2', 85, 200], index=df.columns),
          pd.Series(['item3', 75, 300], index=df.columns),
          pd.Series(['item4', 65, 400], index=df.columns),
          pd.Series(['item5', 55, 500], index=df.columns),
          pd.Series(['item6', 45, 600], index=df.columns),
          pd.Series(['item7', 35, 700], index=df.columns),
          pd.Series(['item8', 25, 800], index=df.columns),
          pd.Series(['item9', 15, 900], index=df.columns)
          ]

df = df.append(sample, ignore_index=True)

print('Data frame')
print(df)

print('Loop with multiply conditions')
for ind, line in (df.loc[
                    (df['ITEM'] == 'item2') |
                    ((df['NUMBER'] >= 30) & (df['PRICE'] <= 300))
                ]).iterrows():
    print(line['ITEM'])
    df.at[ind, 'PRICE'] = 999

print('Modified data frame')
print(df)
Modified data frame
    ITEM NUMBER PRICE
0  item1     95   999
1  item2     85   999
2  item3     75   999
3  item4     65   400
4  item5     55   500
5  item6     45   600
6  item7     35   700
7  item8     25   800
8  item9     15   900

Формирование первоначального df сделано с помощью Series чтобы можно было дальше добавлять новые строки. Иначе у меня не получалось(сформировать df, потом еще какой-то кусок и добавить его к первоначальному df).

P.S. Комментарии по оптимизации сильно приветствуются. Может чукча(который не сварщик) чего-то не нашел, хотя старался.

Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.