Параметризованные строковые форматы дают неожиданные результаты - PullRequest
0 голосов
/ 08 сентября 2018

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

В конечном итоге я хочу использовать этот фрейм данных, чтобы создать словарь преобразователя для каждой переменной, передаваемой в вызов pd.read_csv, где функция преобразователя лямбда-преобразователь строки с параметризованной шириной, которая варьируется для каждой переменной.

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

  • Для этого я перебираю строки и использую переменную, обозначающую ширину, для создания выражения форматирования строки с переменной шириной. Это похоже на работу.

  • Я храню этот форматер в словаре с записью для каждой строки.

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

Пример:

# dict for storing the mapping
coll={}

# mock data (var name and associated width)
df=pd.DataFrame(data={'nme':['a','b','c','d'],'width':[2,2,3,4]})

# iterate rows
for _,dta in df.iterrows():

    # create variable width format string from width variable
    # mix of old / new string format approach

    formatstring = ('{:0>%s}'%dta.width)

    # turn string into a function, with string to be padded as argument

    formatfunc = lambda x: formatstring.format(x)
    coll[dta.nme]=formatfunc

    print 'var {}; width {}'.format(dta.nme, dta.width)
    print formatstring

И текущий вывод выглядит следующим образом - в частности, формататор строк выглядит кошерно, с переменной шириной .:

var a; width 2
{:0>2}
var b; width 2
{:0>2}
var c; width 3
{:0>3}
var d; width 4
{:0>4}

Но когда я набираю запись в словаре coll, я неизменно получаю отступ до длины 4. Что я пропустил, и это практический подход?

coll['a'](3)
'0003'

Здесь я ожидал дополненную строку длиной 2 для ключа a. Вместо этого я получаю длину 4.

1 Ответ

0 голосов
/ 09 сентября 2018

Это потому, что ваша лямбда при вычислении использует глобальную переменную formatstring. formatstring равно {:0>4}, значение, установленное для него в последней итерации.

Еще один более простой пример:

y = 5
f = lambda x: print(x+y)
f(2) # prints 7
y = 10
f(2) # prints 12


Как решить эту проблему

Один из способов решить эту проблему - полностью избавиться от лямбд. Хакерский пример:

df.set_index('nme',inplace=True)
coll = df.to_dict(orient='index')   

'0'*coll['a']['width']+str(3)  # prints '003'

Вы можете преобразовать последнюю строку в функцию (или лямбду), если хотите.

...