As PEP 3101, string.format(**other_dict) is not available.
If the index or keyword refers to an item that does not exist, then an IndexError/KeyError should be raised.
A hint for solving the problem is in Customizing Formatters, PEP 3101. That uses string.Formatter.
I improve the example in PEP 3101:
from string import Formatter
class UnseenFormatter(Formatter):
def get_value(self, key, args, kwds):
if isinstance(key, str):
try:
return kwds[key]
except KeyError:
return key
else:
return Formatter.get_value(key, args, kwds)
string = "{number_of_sheep} sheep {has} run away"
other_dict = {'number_of_sheep' : 1}
fmt = UnseenFormatter()
print fmt.format(string, **other_dict)
The output is
1 sheep has run away
Answer from emesday on Stack OverflowAs PEP 3101, string.format(**other_dict) is not available.
If the index or keyword refers to an item that does not exist, then an IndexError/KeyError should be raised.
A hint for solving the problem is in Customizing Formatters, PEP 3101. That uses string.Formatter.
I improve the example in PEP 3101:
from string import Formatter
class UnseenFormatter(Formatter):
def get_value(self, key, args, kwds):
if isinstance(key, str):
try:
return kwds[key]
except KeyError:
return key
else:
return Formatter.get_value(key, args, kwds)
string = "{number_of_sheep} sheep {has} run away"
other_dict = {'number_of_sheep' : 1}
fmt = UnseenFormatter()
print fmt.format(string, **other_dict)
The output is
1 sheep has run away
Can't see the advantage. You have to check the plurality anyway, cause normally you don't have a fixed number of sheep
class PluralVerb(object):
EXCEPTIONS = {'have': 'has'}
def __init__(self, plural):
self.plural = plural
def __format__(self, verb):
if self.plural:
return verb
if verb in self.EXCEPTIONS:
return self.EXCEPTIONS[verb]
return verb+'s'
number_of_sheep = 4
print "{number_of_sheep} sheep {pl:run} away".format(number_of_sheep=number_of_sheep, pl=PluralVerb(number_of_sheep!=1))
print "{number_of_sheep} sheep {pl:have} run away".format(number_of_sheep=number_of_sheep, pl=PluralVerb(number_of_sheep!=1))
You can't do it within the format string itself, but using named placeholders, you can pass a dict-like thing to .format_map that contains a generic default value, or combine a dict of defaults for each value with the provided dict to override individually.
Examples:
With a defaulting
dict-like thing:from collections import Counter fmt_str = "I have {spam} cans of spam and {eggs} eggs." print(fmt_str.format_map(Counter(eggs=2)))outputs
I have 0 cans of spam and 2 eggs.With combining
dictof defaults:def format_groceries(**kwargs): defaults = {"spam": 0, "eggs": 0, **kwargs} # Defaults are replaced if kwargs includes same key return "I have {spam} cans of spam and {eggs} eggs.".format(defaults) print(format_groceries(eggs=2))which behaves the same way.
With numbered placeholders, the solutions end up uglier and less intuitive, e.g.:
def format_up_to_two_things(*args)
if len(args) < 2:
args = ('default text', *args)
return "Text {0} here, and text {1} there".format(*args)
The tutorial doesn't really go into this because 99% of the time, modern Python is using f-strings, and actual f-strings generally don't need to deal with this case, since they're working with arbitrary expressions that either work or don't work, there's no concept of passing an incomplete set of placeholders to them.
If you only needed to insert an exact number of values positionally
as a lambda
meh = lambda x='default x',y='default y': 'Text {0} here, Text {1} here'.format(x,y)
print(meh(3,7))
as a function
def meh(x='default x',y='default y'):
return "Text {0} here, Text {1}".format(x,y)
print(meh(3,7))
string formatting - How to get Python to gracefully format None and non-existing fields - Stack Overflow
python - string.format() with optional placeholders - Stack Overflow
python - String format with optional dict key-value - Stack Overflow
Python default parameter with format() - Stack Overflow
The recommendation in PEP 3101 is to subclass Formatter:
import string
class PartialFormatter(string.Formatter):
def __init__(self, missing='~~', bad_fmt='!!'):
self.missing, self.bad_fmt=missing, bad_fmt
def get_field(self, field_name, args, kwargs):
# Handle a key not found
try:
val=super(PartialFormatter, self).get_field(field_name, args, kwargs)
# Python 3, 'super().get_field(field_name, args, kwargs)' works
except (KeyError, AttributeError):
val=None,field_name
return val
def format_field(self, value, spec):
# handle an invalid format
if value==None: return self.missing
try:
return super(PartialFormatter, self).format_field(value, spec)
except ValueError:
if self.bad_fmt is not None: return self.bad_fmt
else: raise
fmt=PartialFormatter()
data = {'n': 3, 'k': 3.141594, 'p': {'a': '7', 'b': 8}}
print(fmt.format('{n}, {k:.2f}, {p[a]}, {p[b]}', **data))
# 3, 3.14, 7, 8
del data['k']
data['p']['b'] = None
print(fmt.format('{n}, {k:.2f}, {p[a]:.2f}, {p[b]}', **data))
# 3, ~~, !!, ~~
As set up, it will print ~~ if a field or attribute is not found and !! if an invalid format is used given the field value. (Just use None for the keyword argument bad_fmt if you want the default of a value error raised.)
To handle missing keys, you need to subclass both get_field to catch the KeyError or AttributeError and format_field to return a default value for the missing key.
Since you are catching format_field errors, you can catch a bad format field as well by catching the ValueError from the superclass.
If you're able to do the formatting separately you could use Template.safe_substitute which gracefully handles missing values:
>>> from string import Template
>>> t = Template("
b $c")
>>> t.safe_substitute(a=3)
'3
c'
Here is one option:
from collections import defaultdict
my_csv = '{d[first]},{d[middle]},{d[last]}'
print( my_csv.format( d=defaultdict(str, first='John', last='Doe') ) )
"It does{cond} contain the the thing.".format(cond="" if condition else " not")
Thought I'd add this because it's been a feature since the question was asked, the question still pops up early in google results, and this method is built directly into the python syntax (no imports or custom classes required). It's a simple shortcut conditional statement. They're intuitive to read (when kept simple) and it's often helpful that they short-circuit.
Use defaultdict, this will allow you to specify a default value for keys which don't exist in the dictionary. For example:
>>> from collections import defaultdict
>>> d = defaultdict(lambda: 'UNKNOWN')
>>> d.update({'greetings': 'hello'})
>>> '%(greetings)s %(name)s !!!' % d
'hello UNKNOWN !!!'
>>>
Some alternates to defaultDict,
greeting_dict = {'greetings': 'hello'}
if 'name' in greeting_dict :
opening_line = '{greetings} {name}'.format(**greeting_dict)
else:
opening_line = '{greetings}'.format(**greeting_dict)
print opening_line
Maybe even more succinctly, use dictionary get to set per parameter defaults,
'{greetings} {name}'.format(greetings=greeting_dict.get('greetings','hi'),
name=greeting_dict.get('name',''))
You need to either reassign a to a = a.format(one=one, two=two) or simply return it.
return a.format(one=one, two=two)
a.format does not change the original string a, strings are immutable so all a.format does is create a new string. Any time you modify a string it creates a new object. Unless you are using concatenation then to change the value of a you need to reassign a to the new object.
str.replace is another example where people get caught:
In [4]: a = "foobar"
In [5]: id(a)
Out[5]: 140030900696000
In [6]: id(a.replace("f","")) # new object
Out[6]: 140030901037120
In [7]: a = "foobar"
In [8]: a.replace("f","")
Out[8]: 'oobar'
In [9]: a # a still the same
Out[9]: 'foobar'
In [10]: id(a)
Out[10]: 140030900696000
In [11]: a = a.replace("f","") # reassign a
In [12]: id(a)
Out[12]: 140030900732000
In [13]: a
Out[13]: 'oobar'
The line
a.format(one=one, two=two)
is the problem. Since strings are immutable, what happens on this line is the interpreter formats the way you expected it to, but it doesn't assign the value back to a (strings are immutable).
So when you
return a
Your a is still the unformatted a from before.
The solution is to combine these two lines into
return a.format(one=one, two=two)
In response to the follow-up question:
logging.debug(whatever) may not show up because logging may not have been configured to show the DEBUG level. To correct this, use the basicConfig function:
import logging
logging.basicConfig(level=logging.DEBUG)
Consider the following class:
class Team:
def __init__(self, team_members, the_captain):
...Here team_members is a list of strings and the_captain is a string. Now if the_captain is not passed to the constructor, team captain will be selected randomly from team members, otherwise team captain will be the_captain.
I want to set a default value for the_captain, What do you recommend for the default value, None or empty string? In other words which of the following constructor definitions do you think is better?
1
class Team:
def __init__(self, team_members, the_captain=None):
...2
class Team:
def __init__(self, team_members, the_captain=""):
...Thanks