这是使用str.format()的可接受方式吗?

时间:2013-03-28 19:11:45

标签: python coding-style formatting

我最近决定开始使用.format()而不是%(请参阅this question)。而不是{0}{1}语法,我想知道以下是否可以接受:

import os
def get_filename(player_name):
    for ext in ('jpg', 'jpeg', 'png'):
        filename = "data/avatars/{player_name}.{ext}".format(**locals())
        if os.path.exists(filename):
            return filename
    return None

我喜欢它的直截了当 - 局部变量进入字符串 - 但我想知道是否有任何理由我不应该这样做。

2 个答案:

答案 0 :(得分:4)

locals()(或globals())传递给format(或%)的主要问题是格式字符串通常来自不受信任的来源,而且风险很大暴露你不想要的变量。如果您只是格式化文字字符串,那不是问题,但如果您可能有不受信任的格式字符串,则必须非常仔细地考虑您正在做什么 - 并且更容易做到这一点。< / p>

更小的问题是,您的某些代码的读者不会理解locals**语法,并且很难弄清楚它的作用或原因。这不是一个争论。事实上,你甚至可以说许多Python的设计决定都是为了确保这几乎不是一个好的论据 - 语言非常大,以至于期望读者理解/学习你写的任何pythonic是合理的。但它仍然值得考虑。

然后是风格问题。每隔几个月,有人会提出这种语言应该更容易做到这一点,并在邮件列表上开始论证。有些人肯定认为这感觉“隐含而不是明确”。其他人不同意。我认为很好地解决了这里的魔术本地人不会是pythonic ......但是如果你必须明确传递locals(),也许那很好,也许不是。像大多数尚未达成共识的风格论点一样,这取决于你。 (顺便说一下,format API最终来自这样的论点,其中最初的建议是使用隐式locals进行更多类似perl的字符串插值。)

但最终,你必须考虑你在节省什么。比较一下:

filename = "data/avatars/{player_name}.{ext}".format(**locals())

为:

filename = "data/avatars/{0}.{1}".format(player_name, ext)

您的版本不够清晰,更明确,更容易打字,甚至更短。所以,我会说让新手阅读有点困难的风险,并且对社区的某些部分感到烦恼(即使是出于不好的原因),如果没有任何好处,那就不值得。

答案 1 :(得分:1)

正如我上面评论的那样,不应该在不受信任的来源上使用它。也许我不太明确地说是Pythonic。

还可以定义一个函数来做到这一点,但要访问正确的本地人,它需要做一些帧处理

def format_locals(string):
    return string.format(**sys._getframe().f_back.f_locals)

这种模式不太好,像Pypy这样的东西不能选择这种代码。

我会使用这段代码(除非你需要Python 2.6支持,所以你必须添加索引):

filename = 'data/avatars/{}.{}'.format(player_name, ext)
相关问题