2

我最近决定开始使用.format()而不是%(请参阅此问题)。而不是{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

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

4

2 回答 2

4

locals()将(or globals()) 传递给format(or )的主要问题%是,格式字符串通常可能来自不受信任的来源,并且您可能会暴露您不想要的变量。如果你只是格式化一个文字字符串,那不是问题,但如果你可能有不受信任的格式字符串,你必须非常仔细地考虑你在做什么——而且不这样做会更容易。

更小的问题是您的代码的某些读者不理解locals**语法,并且很难弄清楚它的作用或工作原理。这没什么好争论的。事实上,你甚至可以说 Python 的许多设计决策都归结为确保这几乎不是一个好的论点——该语言足够大,可以合理地期望你的读者理解/学习你编写的任何 Python 语言。但这仍然值得思考。

然后是风格问题。每隔几个月,就会有人提出建议该语言应该更容易做到这一点,并在邮件列表上引发争论。有些人肯定认为这感觉“隐而不显”。其他人不同意。我认为这里的魔法本地人不会是 pythonic 已经很好解决了……但如果你必须明确地通过locals(),也许这很好,也许不是。像大多数尚未达成共识的风格论点一样,这完全取决于您。(顺便说一句,formatAPI 最终产生了这样的论点,其中最初的建议是使用隐式的更像 perl 的字符串插值locals。)

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

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

到:

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

你的版本不是更清晰、更明确、更容易输入,甚至更短。所以,如果没有好处,我想说让新手阅读变得更难一些,并且让社区的某些部分感到烦恼(即使是出于不好的原因)的风险是不值得的。

于 2013-03-28T19:25:05.987 回答
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)
于 2013-03-28T19:28:23.290 回答