Read and reformat a list of global variables output by a compiler I'm currently going through a large Python program, with an eye to making it more readable and maintainable. Currently using Pylint and other code review tools throws a lot of unused variable warnings because of the way I've been using .format(). Since this program manipulates a lot of text, I use .format() quite a lot, which results in many spurious warnings. I could turn these warnings off, but I'd rather not because so far they've been useful in finding genuinely unused variables in my code.

Here's an example of the existing code style. (The program is very large so this is just the tip of the iceberg, selected to show the difference in style that I'm considering. Its purpose is to read and process compiler output, which will then be fed to another set of tools. This particular function is from a module which reads and reformats a list of global variables output by a compiler. The names of some other internal functions have been modified a bit to make it easier to read out of context.)

def parse_global_variable(line, length):
    last_element = length-1
    template = ''
    if length == 0:
        template = ' Record   GLB  {logical_address} {physical_address} {module:34}{var_name}' \
                   '\n                0    {width:7}{var_type}'
    else:
        template = ' Record   GLB  {logical_address} {physical_address} {module:34}{var_name}' \
                   '(0..{last_element})\n                0    {width:7}{var_type}'
    module = line.partition('.')[0].rpartition('\t')[2]
    logical_address = line.partition('#')[2].partition('#')[0]
    physical_address = get_physical_address(logical_address)
    var_name = get_var_name(line))
    width = line.rpartition('\t')[2]
    if length != 0:
        width = str(int(width)/length)
    return template.format(**locals())


This is a different style I'm considering, which inlines most of the variables, shortens variable names in the template string, and uses explicit arguments to .format() instead of using **locals():

def parse_global_variable(line, length):
    template = ''
    if length == 0:
        template = ' Record   GLB  {la} {pa} {m:34}{vn}' \
                   '\n                0    {w:7}{vt}'
    else:
        template = ' Record   GLB  {la} {pa} {m:34}{vn}(0..{le})' \
                   '\n                0    {w:7}{vt}'
    logical_address = line.partition('#')[2].partition('#')[0]
    width = line.rpartition('\t')[2]
    if length != 0:
        width = str(int(width)/length)
    return template.format(la=logical_address, pa=get_physical_address(logical_address), 
        m=line.partition('.')[0].rpartition('\t')[2], vn=get_var_name(line), le=length-1, w=width)


Is it stylistically preferable, more readable, more Pythonic, etc. to use **locals() or explicit arguments? Is using abbreviated names such as vn or pa in the format string frowned upon when there are explicit arguments? And should variables which are only used in the format string be inlined?

Edit: Here is a sample input line:

Record      imsd_ini.ini            16#3200#        0       1424


The output that this module produces corresponding to that line is:

Record   GLB  3200 133200 imsd_ini                          ini
              0    1424   ini_type
The docs for locals() imply that there's some overhead involved with using it: 


  Update and return a dictionary representing the current local symbol table. Free variables are returned by locals() when it is called in function blocks, but not in class blocks.


So it might be best to avoid it from that perspective alone.  (Though it's probably fine in most cases, and avoiding it might be a case of premature optimization.)

I generally prefer verbose format strings when using them this way, using the philosophy of "If the string was separated from the code that uses it, could someone still figure out what each variable in the string is referring to?".  So I frequently end up doing somewhat of a hybrid approach -- using a dictionary for the format arguments rather than locals() and rather than having to repeat every single argument as a keyword argument:

def parse_global_variable(line, length):
    last_element = length-1
    template = ''  # This is actually redundant

    f = {
        'module': line.partition('.')[0].rpartition('\t')[2],
        'logical_address': line.partition('#')[2].partition('#')[0],
        'var_name': get_var_name(line),
        'width': line.rpartition('\t')[2]
    }
    f['physical_address'] = get_physical_address(f['logical_address'])

    if length == 0:
        template = ' Record   GLB  {logical_address} {physical_address} {module:34}{var_name}' \
                   '\n                0    {width:7}{var_type}'
    else:
        template = ' Record   GLB  {logical_address} {physical_address} {module:34}{var_name}' \
                   '(0..{last_element})\n                0    {width:7}{var_type}'
        f['width'] = str(int(f['width'])/length)
    return template.format(**f)