简体   繁体   中英

Default kwarg values for Python's str.format() method

I'm looking to try and keep pluralisation of existing strings as simple as possible, and was wondering if it was possible to get str.format() to interpret a default value when looking for kwargs. Here's an example:

string = "{number_of_sheep} sheep {has} run away"
dict_compiled_somewhere_else = {'number_of_sheep' : 4, 'has' : 'have'}

string.format(**dict_compiled_somewhere_else)
# gives "4 sheep have run away"

other_dict = {'number_of_sheep' : 1}
string.format(**other_dict)
# gives a key error: u'has'
# What I'd like is for format to somehow default to the key, or perhaps have some way of defining the 'default' value for the 'has' key 
# I'd have liked: "1 sheep has run away"

Cheers

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

Based on mskimm and Daniel answer, here's a solution that predefines the singular/plural words (whilst correcting a couple of typos in mskimm's).

The only downside is the hard coding of the keyword arg number (so I can no longer use number_of_sheep )

from string import Formatter

class Plural(Formatter):
    PLURALS = {'has' : 'have'}
    def __init__(self):
        super(Plural, self).__init__()

    def get_value(self, key, args, kwds):
        if isinstance(key, str):
            try:
                return kwds[key]
            except KeyError:
                if kwds.get('number', 1) == 1:
                    return key
                return self.PLURALS[key]
        return super(Plural, self).get_value(key, args, kwds)

string = "{number} sheep {has} run away"
fmt = Plural()
print fmt.format(string, **{'number' : 1})
print fmt.format(string, **{'number' : 2})

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))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM