문제

Is there any way to pass an "empty" numeric type into a numeric format specifier and have it print the blank space associated with that specifier?

ie.

n = "Scientific:"
v = 123.321
strfmt = "%5.4E"
output = "%s|"+strfmt+"|"
print output % (n, v)

>   Scientific:|1.2332E+02|

v = EMPTY
print output % (n, v)

>   Scientific:|          |

The ultimate goal is to deal with incomplete lines without adaptively changing the format string while looping

perline = 3
n = ["1st:","2nd:","3rd:","4th:","5th:","6th:"]
v = [1.0, 2.0, 3.0, 4.0]

strfmt = "%5.4E"
output = ("%s|"+strfmt+"|  ")*perline+"\n"

for args in map(EMPTY,*[iter(n),iter(v)]*perline):
    print output % args

>   1st:|1.0000E+00|  2nd:|2.0000E+00|  3rd:|3.0000E+00|
>   4th:|4.0000E+00|  5th:|          |  6th:|          |

To execute the above code I replaced EMPTY with None although that gives an error when you pass None to the format string

도움이 되었습니까?

해결책 6

After viewing the responses it appears that there is no thing you can pass to a numeric format specifier to have it print the blank space associated with it.

There are a number of ways to work around this shown below. Personally I liked parts of Unutbu's answer. I think the way I will ultimately do it is create two format specifiers at the beginning and use logic as suggested by Blender.

다른 팁

You won't be able to do it with just number formatting. You'll need some logic:

strfmt = "%5.4E"
v = None

if v in [None, '']:
  output = "%s|          |"
else:
  output = "%s|"+strfmt+"|"

Short answer: for a field n positions wide, '%​n​s' % '' will do. That is, to '%15s' % '' will print 15 spaces.

Long answer: when you specify a width in format specifiers, the first number is the minimum width of the entire field. "%5.4E" will take more than 5 places, though, because just the exponent will take 3 places already.

Specify something like "%12.4E" and get consistent results. For missing values, specify "%12s" and pass an empty string (not None) instead of the value.

One option would be to replace the numeric format in output with %s, and then in the replacing tuple create either the correct numeric output or the empty space depending on what v is:

>>> v = 123.321
>>> "%s|%s|" % (n, "%5.4E" % v if v is not None else " "*10)
'Scientific:|1.2332E+02|'
>>> v = None
>>> "%s|%s|" % (n, "%5.4E" % v if v is not None else " "*10)
'Scientific:|          |'

You could make this a little more functional with a simple closure:

def make_default_blank_formatter(format, default):
    def default_blank_formatter(v):
        return format % v if v is not None else default
    return default_blank_formatter

scientific_formatter = make_default_blank_formatter("%5.4E", " "*10)

>>> v = 123.321
>>> "%s|%s|" % (n, scientific_formatter(v))
'Scientific:|1.2332E+02|'
>>> v = None
>>> "%s|%s|" % (n, scientific_formatter(v))
'Scientific:|          |'

edit: Here is how you could rework your printing code to use this:

perline = 3
n = ["1st:","2nd:","3rd:","4th:","5th:","6th:"]
v = [1.0, 2.0, 3.0, 4.0, None, None]

strfmt = "%5.4E"
output = ("%s|%s|  ")*perline

for args in zip(*[iter(n),iter(map(scientific_formatter, v))]*perline):
    print output % args

You could use itertools.izip_longest to pair the items in n and v, and fill in missing values with the empty string.

To get the proper formatting for the items in v, you could pre-format the floats with strfmt, and use something like

output = "%s|%10s|  "

to join the items in n and v. By doing it this way, the items in v are now all strings, including the empty strings, and not a mixture of floats and empty strings.


import itertools

perline = 3
n = ["1st:", "2nd:", "3rd:", "4th:", "5th:", "6th:"]
v = [1.0, 2.0, 3.0, 4.0]

strfmt = "%5.4E"
v = (strfmt % val for val in v)
output = "%s|%10s|  "

pairs = itertools.izip_longest(n, v, fillvalue = '')
items = (output % (place, val) for place, val in pairs)
for row in zip(*[items]*perline):
    print(''.join(row))

yields

1st:|1.0000E+00|  2nd:|2.0000E+00|  3rd:|3.0000E+00|  
4th:|4.0000E+00|  5th:|          |  6th:|          |  

As suggested above, just convert your numbers to strings before printing, and replace missing numbers with empty strings of the equal length. This can be actually written very compact, however I would never use this in serious code:

from itertools import izip_longest, groupby, chain

perline = 3
n = ["1st:","2nd:","3rd:","4th:","5th:","6th:"]
v = [1.0, 2.0, 3.0, 4.0]

strfmt = "%5.4E"
output = ("%s|%s|  ")*perline

for _, args in groupby(enumerate(chain(*izip_longest(n, (strfmt % x for x in v),
                                                     fillvalue = ' '*len(strfmt % 0)))),
                       lambda (i, v): i/perline/2):
    print output % zip(*args)[1]

More readable and reliable version of the last loop:

l = ()
for pair in izip_longest(n, (strfmt % x for x in v),
                         fillvalue = ' '*len(strfmt % 0)):
    l += pair
    if len(l) == perline*2:
        print output % l
        l = ()
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top