Key Error when trying to format columns use variables python 3

813 views Asked by At

I am trying to format a group of columns in python 3. So far I have not had much luck. I managed to get the columns to print, but I can't get them to line up. I am trying to make each column dynamic so that it can adapt if different information needs to be printed. But because I am trying to use variables in the column formatting, I keep getting Key Errors. Any idea how I can fix this?

Indicator                              :Min                                   :Max                                   
----------------------------------------------------------------------------
Traceback (most recent call last):
  File "G:/test.py", line 154, in <module>
    print('{heart:{heart_col_width}}:{motor:{motor_col_width}} {teen:{teen_col_width}{smoke:        {smoke_col_width}}{obese:{obese_col_width}'.format(heart, motor, teen, smoke, obese ))
KeyError: 'heart'

This is the code I am using.

first_row = ['Indicator',':Min',':Max']

col_width = max(len(word) for word in first_row) +20# padding

print ("".join(word.ljust(col_width) for word in first_row))

print('----------------------------------------------------------------------------')

heart=['Heart Disease Death Rate     (2007)',stateheart_min(),heartdis_min(),stateheart_max(),heartdis_max()]
motor=[ 'Motor Vehicle Death Rate     (2009)',statemotor_min(),motordeath_min(),statemotor_max(),motordeath_max()]
teen=['Teen Birth Rate (2009)',stateteen_min(),teenbirth_min(),stateteen_max(),teenbirth_max()]
smoke=['Adult Smoking     (2010)',statesmoke_min(),adultsmoke_min(),statesmoke_max(),adultsmoke_max()]
obese=['Adult Obesity     (2010)',stateobese_min(),adultobese_min(),stateobese_max(),adultobese_max()]

heart_col_width = max(len(word) for word in heart)
motor_col_width = max(len(word) for word in motor)
teen_col_width = max(len(word) for word in teen)
smoke_col_width = max(len(word) for word in smoke)
obese_col_width = max(len(word) for word in obese)


for heart, motor, teen, smoke, obese in zip(heart, motor, teen, smoke, obese ):
    print('{heart:{heart_col_width}}:{motor:{motor_col_width}} {teen:{teen_col_width}{smoke:    {smoke_col_width}}{obese:{obese_col_width}'.format(heart, motor, teen, smoke, obese ))
1

There are 1 answers

0
Savir On

When you use

"{whatever}".format(whatever)

the format function doesn't know how to "match" or "connect" the whatever in "{whatever}" to the whatever in format(whatever) For the interpreter, they have nothing to do with each other. When the .format function sees the "{whatever}" it will try to look for a keyword argument whatever in its call, but there's none. It only knows that there's a positional argument (which is not the droid... erm... the argument that it's looking for)

You might want to understand what positional arguments are versus keyword arguments (check this SO thread) In general, you're gonna need to know that difference very well for any Python development that you work on.

Knowing that, let's go back to the .format method:

You need to explicitly tell the .format method the connection between the two whatevers:

"{whatever}".format(whatever=whatever)

Maybe it's clearer by doing:

foo="hello"
"{whatever}".format(whatever=foo)
#   ^                 ^
#   |_________________|

So in your case, you can do:

for heart, motor, teen, smoke, obese in zip(heart, motor, teen, smoke, obese ):
    print(
        '{heart:{heart_col_width}}:{motor:{motor_col_width}}'
        ' {teen:{teen_col_width}{smoke:{smoke_col_width}}'
        ' {obese:{obese_col_width}'.format(
            heart=heart, heart_col_width=heart_col_width,
            motor=motor, motor_col_width=motor_col_width,
            teen=teen, teen_col_width=teen_col_width,
            smoke=smoke, smoke_col_width=smoke_col_width,
            obese=obese, obese_col_width=obese_col_width)
    )

Thanks to the use of these keyword arguments, if the column width is the same for all the columns, you don't need to re-specify it. You can just reuse them in different parts of your string:

heart = "hello"
motor = "goodbye"
filler = 10
print (
    "{heart:{filler}} someting something {motor:{filler}} something something"
    .format(heart=heart, motor=motor, filler=filler)
)

Check this string formatting tutorial (particularly its examples section). It might give you some alternative ideas.