我最近决定开始使用.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
我喜欢它的直截了当 - 局部变量进入字符串 - 但我想知道是否有任何理由我不应该这样做。
答案 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)