PEP8, locals() and interpolation



这里有一些代码:

foo = "Bears"
"Lions, Tigers and %(foo)s" % locals()

我的PEP8 linter(SublimeLinter)对此抱怨,因为foo是"未引用的"。我的问题是,PEP8是否应该将这种类型的字符串插值算作"引用",或者是否有充分的理由考虑这种"糟糕的风格"。

嗯,它没有被引用。风格有问题的部分是使用locals()访问变量,而不是仅通过名称访问它们。请参阅前面的问题,了解为什么这是一个可疑的想法。这不是一件可怕的事情,但对于一个你想长期维持的程序来说,这不是一个好的风格。

编辑:确实,当您使用文字格式字符串时,它看起来更明确。但上一篇文章的部分要点是,在一个更大的程序中,您可能会使用文本格式字符串来结束而不是。如果它是一个小程序,而你不在乎,那就继续使用它。但是,对以后可能导致可维护性问题的事情发出警告也是样式指南和linters的作用之一。

此外,locals并不是文字中明确引用的名称的规范表示。它是本地命名空间中所有名称的规范表示。如果你喜欢的话,你仍然可以这样做,但这基本上是一个松散/草率的选择,而不是明确使用你正在使用的名称,这也是linters应该警告你的事情。

即使您拒绝BrenBarn关于foo未被引用的论点,如果您接受以字符串格式传递locals()的论点,则可能不值得编写代码来考虑引用foo

首先,在所有额外代码会有所帮助的情况下,该构造无论如何都是不可接受的,用户无论如何都必须忽略lint警告。是的,当实际上只有一个问题时,给用户两个lint警告而忽略会有一些危害,尤其是如果其中一个警告有误导性的话。但是,这足以证明编写非常复杂的代码并在linter中引入新的bug是合理的吗?

您还必须考虑到,要使其真正起作用,linter不仅要识别%格式,还要识别{}格式,以及用户可能使用的所有其他类型的字符串格式、HTML模板等。在实践中,这意味着处理各种非常常见的形式,并为用户提供某种钩子来描述其他内容。

最重要的是,即使你认为它不应该使用任意生成的格式字符串,它也必须至少使用l10n。这怎么办?如果格式字符串是由gettext之类的东西生成的,则linter无法知道foo是否被引用,除非它能够检查所有翻译,并看到其中至少有一个引用了foo——这意味着它必须理解(或教授挂钩)每个字符串翻译机制,并能够访问翻译数据库。

所以,我建议,即使你认为在这种情况下警告是虚假的,你也要把它留在那里。最多添加一些符合警告条件的内容:

foo可能未被引用,但在使用locals()的函数中

下面的内容也不会让SublimeLinter满意,它查找字符串中引用的每个变量名,并替换命名空间映射中的相应值,默认为调用方的locals。因此,它显示了SublimeLinter这样的实用程序在试图确定Python中是否引用了某个内容时所具有的固有限制)。我的建议是忽略SublimeLinter,或者添加代码来伪造它,比如foo = foo。我不得不做一些类似于后者的事情来消除C编译器对合法和有意的事情的警告。

import re
import sys
SUB_RE = re.compile(r"%((.*?))s")
def local_vars_subst(s, namespace=None):
if namespace is None:
namespace = sys._getframe(1).f_locals
def repl(matchobj):
var = matchobj.group(1).strip()
try:
retval = namespace[var]
except KeyError:
retval = "<undefined>"
return retval
return SUB_RE.sub(repl, s)
foo = "Bears"
print local_vars_subst("Lions, Tigers and %(foo)s")

最新更新