Pull to refresh

Решил как-то абапер питон выучить. Часть 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. Комментарии по оптимизации сильно приветствуются. Может чукча(который не сварщик) чего-то не нашел, хотя старался.

Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.