Search code examples
pythonstringstring-formattingtabexpansion

Use different values of expandtabs() in the same string - Python


How can we define several tab lengths in a python string? For example, we want to print the keys, value types and values of a dict nicely aligned (with varying sizes of keys and types):

my_dict = {
    "short_key": 4,
    "very_very_very_very_very_long_keys": 5.0
}

formatted_string_1 = '\n'.join([f"{k}:\t({type(v).__name__})\t{v}".expandtabs(10) for k, v in my_dict.items()])
print(f"Option 1 (.expandtabs(10)), first tab is too small:\n{formatted_string_1}")

formatted_string_2 = '\n'.join([f"{k}:\t({type(v).__name__})\t{v}".expandtabs(40) for k, v in my_dict.items()])
print(f"\n\nOption 2 (.expandtabs(40)), second tab is too large:\n{formatted_string_2}")

Running this we get:

Option 1 (.expandtabs(10)), first tab is too small:
short_key:          (int)     4
very_very_very_very_very_long_keys:     (float)   5.0

and:

Option 2 (.expandtabs(40)), second tab is too large:
short_key:                              (int)                                   4
very_very_very_very_very_long_keys:     (float)                                 5.0

I would like to be able to define a long tab for the first space, and a short tab for the second one, something like .expandtabs([40, 10]), such that we get two nice alignments:

short_key:                              (int)     4
very_very_very_very_very_long_keys:     (float)   5.0

Any idea?


Solution

  • Don't use tabs for alignment. You can specify your desired widths directly in the f-string's format spec:

    print(
        '\n'.join(
            f"{f'{k}:':40}"
            f"{f'({type(v).__name__})':10}"
            f"{v:<}" 
            for k, v in my_dict.items()
        )
    )
    

    outputs

    short_key:                              (int)     4
    very_very_very_very_very_long_keys:     (float)   5.0
    

    You can even use variable widths computed from the members of my_dict:

    key_width = max(len(k) for k in my_dict) + 6
    type_width = max(len(type(v).__name__) for v in my_dict.values()) + 5
    
    print(
        '\n'.join(
            f"{f'{k}:':{key_width}}"
            f"{f'({type(v).__name__})':{type_width}}"
            f"{v:<}" 
            for k, v in my_dict.items()
        )
    )
    

    which again outputs

    short_key:                              (int)     4
    very_very_very_very_very_long_keys:     (float)   5.0