Use parameter in format string - python

This:
print '{:x<4d}'.format(34)
prints this:
34xx
How can I do this:
width = 13
print '{:x<|width|d}'.format(34)
to get this:
34xxxxxxxxxxx

You can put one format field inside of the other:
>>> width = 13
>>> print '{:x<{}d}'.format(34, width)
34xxxxxxxxxxx
>>>
From the docs:
A format_spec field can also include nested replacement fields within
it. These nested replacement fields can contain only a field name;
conversion flags and format specifications are not allowed. The
replacement fields within the format_spec are substituted before the
format_spec string is interpreted. This allows the formatting of a
value to be dynamically specified.
Note however that the nesting can only go one level deep.

This works
('{:x<%dd}' % width).format(34)

this will work:
>>> width = 13
>>> print '{:x<{}d}'.format(34,width)
34xxxxxxxxxxx

You can nest arguments in format, using kwargs allows you to be more explicit and less susceptible to confusing results:
fillchar = 'x'
width = 13
print "{:{f}<{w}d}".format(34, w=width, f=fillchar)

Related

Creating new conversion specifier in Python

In python we have conversion specifier like
'{0!s}'.format(10)
which prints
'10'
How can I make my own conversion specifiers like
'{0!d}'.format(4561321)
which print integers in following format
4,561,321
Or converts it into binary like
'{0!b}'.format(2)
which prints
10
What are the classes I need to inherit and which functions I need to modify? If possible please provide a small example.
Thanks!!
What you want to do is impossible, because built-in types cannot be modified and literals always refer to built-in types.
There is a special method to handle the formatting of values, that is __format__, however it only handles the format string, not the conversion specifier, i.e. you can customize how {0:d} is handled but not how {0!d} is. The only things that work with ! are s and r.
Note that d and b already exist as format specifiers:
>>> '{0:b}'.format(2)
'10'
In any case you could implement your own class that handles formatting:
class MyInt:
def __init__(self, value):
self.value = value
def __format__(self, fmt):
if fmt == 'd':
text = list(str(self.value))
elif fmt == 'b':
text = list(bin(self.value)[2:])
for i in range(len(text)-3, 0, -3):
text.insert(i, ',')
return ''.join(text)
Used as:
>>> '{0:d}'.format(MyInt(5000000))
5,000,000
>>> '{0:b}'.format(MyInt(8))
1,000
Try not to make your own and try to use default functions already present in python. You can use,
'{0:b}'.format(2) # for binary
'{0:d}'.format(2) # for integer
'{0:x}'.format(2) # for hexadecimal
'{0:f}'.format(2) # for float
'{0:e}'.format(2) # for exponential
Please refer https://docs.python.org/2/library/string.html#formatspec for more.

Python - convert to string with formatter as parameter

I am trying to write a function which takes two arguments:
an object
a formatter string (as specified in docs)
which then returns a formatted string:
What I tried is sort of:
def my_formatter(x, form):
return str(x).format(form)
What I am expecting is:
s = my_formatter(5, "%2f")
# s = 05
t = my_formatter(5, "%.2")
# t = 5.00
etc...
The format function unfortunately does not work like that. Any ideas?
For that style of formatting you'd have to use the string % values string formatting operation:
def my_formatter(x, form):
return form % x
You'd also have to alter your format; to get 05 you'd have to use "%02d", not "%2f".
You were getting confused by the str.format() method, which uses a different formatting syntax, and you got the arguments swapped; you'd use form.format(x) instead.
You probably want to look into the built-in format() function here; the syntax is slightly different, but offers more features:
>>> format(5, '02d')
'05'
>>> format(5, '.2f')
'5.00'
That's pretty close to what you were already using, minus the %.

How do I specify "%-*s" in new-style .format()?

I would like to translate the following code
print "%-*s" % (10, 'foo')
which would print foo with 7 trailing spaces (field width == 10, left justified), into a Python 3 .format() call, but not having much luck googling.. Is it possible?
'{1:{0}}'.format(10, 'foo')
or with implicit indices:
'{:{}}'.format('foo', 10)
See https://docs.python.org/2/library/string.html#format-string-syntax
This should work.
'{:<10}'.format('foo')
How about this:
"{:<10}".format("foo")
Which will produce (spaces replaced by underscores):
'foo_______'
For more information check out the section Format specification mini-language of the python documentation.

Python: Capitalize a word using string.format()

Is it possible to capitalize a word using string formatting? For example,
"{user} did such and such.".format(user="foobar")
should return "Foobar did such and such."
Note that I'm well aware of .capitalize(); however, here's a (very simplified version of) code I'm using:
printme = random.choice(["On {date}, {user} did la-dee-dah. ",
"{user} did la-dee-dah on {date}. "
])
output = printme.format(user=x,date=y)
As you can see, just defining user as x.capitalize() in the .format() doesn't work, since then it would also be applied (incorrectly) to the first scenario. And since I can't predict fate, there's no way of knowing which random.choice would be selected in advance. What can I do?
Addt'l note: Just doing output = random.choice(['xyz'.format(),'lmn'.format()]) (in other words, formatting each string individually, and then using .capitalize() for the ones that need it) isn't a viable option, since printme is actually choosing from ~40+ strings.
As said #IgnacioVazquez-Abrams, create a subclass of string.Formatter allow you to extend/change the format string processing.
In your case, you have to overload the method convert_field
from string import Formatter
class ExtendedFormatter(Formatter):
"""An extended format string formatter
Formatter with extended conversion symbol
"""
def convert_field(self, value, conversion):
""" Extend conversion symbol
Following additional symbol has been added
* l: convert to string and low case
* u: convert to string and up case
default are:
* s: convert with str()
* r: convert with repr()
* a: convert with ascii()
"""
if conversion == "u":
return str(value).upper()
elif conversion == "l":
return str(value).lower()
# Do the default conversion or raise error if no matching conversion found
return super(ExtendedFormatter, self).convert_field(value, conversion)
# Test this code
myformatter = ExtendedFormatter()
template_str = "normal:{test}, upcase:{test!u}, lowcase:{test!l}"
output = myformatter.format(template_str, test="DiDaDoDu")
print(output)
You can pass extra values and just not use them, like this lightweight option
printme = random.choice(["On {date}, {user} did la-dee-dah. ",
"{User} did la-dee-dah on {date}. "
])
output = printme.format(user=x, date=y, User=x.capitalize())
The best choice probably depends whether you are doing this enough to need your own fullblown Formatter.
You can create your own subclass of string.Formatter which will allow you to recognize a custom conversion that you can use to recase your strings.
myformatter.format('{user!u} did la-dee-dah on {date}, and {pronoun!l} liked it. ',
user=x, date=y, pronoun=z)
In python 3.6+ you can use fstrings now. https://realpython.com/python-f-strings/
>>> txt = 'aBcD'
>>> f'{txt.upper()}'
'ABCD'

variable number of digit in format string

Which is a clean way to write this formatting function:
def percent(value,digits=0):
return ('{0:.%d%%}' % digits).format(value)
>>> percent(0.1565)
'16%'
>>> percent(0.1565,2)
'15.65%'
the problem is formatting a number with a given number of digits, I don't like to use both '%' operator and format method.
I like this one:
'{0:.{1}%}'.format(value, digits)
Test:
>> '{0:.{1}%}'.format(0.1565, 0)
'16%'
>> '{0:.{1}%}'.format(0.1565, 2)
'15.65%'
* does what you want, for printf-style string formatting.
>>> def percent(value, digits=0):
... return '%.*f%%' % (digits, value * 100)
...
>>> percent(0.1565, 2)
'15.65%'
Advanced string formatting (defined in PEP 3101 and documented in 7.1.3. Format String Syntax) doesn't seem to be capable of doing this in one pass. (See 7.1.3.1. Format Specification Mini-Language: precision is integer only.)
From the docs:
Minimum field width (optional). If specified as an '*' (asterisk), the
actual width is read from the next element of the tuple in values, and
the object to convert comes after the minimum field width and optional
precision.
Example:
def percent(value, digits=0):
print '%.*f%%' % (digits, value*100)
>>> percent(0.1565, 2)
15.65%

Categories

Resources