Python的str.format()方法的默认关键字参数值

19

我希望尽可能简化现有字符串的复数形式,并想知道是否可能让str.format()在查找关键字参数时解释默认值。这里是一个例子:

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"

干杯


1
相关:复数字符串格式化 - Ashwini Chaudhary
不错的链接,我应该先看到它。 - Patrick
参见:https://dev59.com/6mIj5IYBdhLWcg3weEwJ - dreftymac
3个回答

30

根据PEP 3101string.format(**other_dict)不可用。

如果索引或关键字指向不存在的项目,则应引发IndexError / KeyError异常。

解决问题的提示在自定义格式化程序PEP 3101中。这使用了string.Formatter

我改进了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)

输出为

1 sheep has run away

1
我认为这是最清晰的方法,除了昨天的帖子中展示的那些方法之外(https://dev59.com/N2Eh5IYBdhLWcg3w7XLt)。在我的评论中,我进行了一些修改,使其更加DRY。 - Patrick
2
PS:附上PEP 3101的链接会很好,也值得一个+1的赞扬;-) - Patrick
1
Formatter.get_value(key, args, kwds) 前缺少 return,没有它位置参数将无法工作。此外,我认为您根本不需要实现 __init__,因为它只调用父类的 __init__ - previous_developer
我可以建议检查isinstance(key, basestring),这样即使键是Unicode,它仍然可以正常工作。 - Derwent

2

看不出有什么优势。无论如何,您都必须检查复数形式,因为通常您没有固定数量的羊。

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

这很好,而且DRY(单数/复数在之前定义),但个人而言,我更喜欢在我的格式字符串中定义单数,并在需要时替换为复数。展示了另一种方法给mskimm的。 - Patrick

1

基于mskimm和Daniel的答案,这里有一个解决方案,预定义了单数/复数词(同时纠正了mskimm中的一些拼写错误)。

唯一的缺点是关键字参数number的硬编码(因此我不能再使用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})

1
一个好的解决方案。我认为问题是关于“安全”替换而不是“复数形式”的。 - emesday
我想你是对的,我表达的意思是安全替换,但我的情况是使用复数形式。不过,你的答案获得了勾选标记 :) - Patrick

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接