对于小型应用程序和所谓的“一次性”脚本来说是可以的,尤其是@kaizer.se 提到的vars 增强和@RedGlyph 提到的.format 版本。
但是,对于维护寿命长且维护人员众多的大型应用程序,这种做法可能会导致维护问题,我认为这就是 @S.Lott 的答案的来源。让我解释一下其中涉及的一些问题,因为对于没有开发和维护大型应用程序(或此类野兽的可重用组件)的任何人来说,它们可能并不明显。
在“严肃”的应用程序中,您不会对格式字符串进行硬编码——或者,如果有的话,它将采用某种形式,例如 _('Hello {name}.'),其中 _ 来自 gettext或类似的 i18n / L10n 框架。关键是这样的应用程序(或可能在此类应用程序中使用的可重用模块)必须支持国际化(AKA i18n)和定位(AKA L10n):您希望您的应用程序能够在某些情况下发出“Hello Paul”国家和文化,其他一些中的“Hola Paul”,其他一些中的“Ciao Paul”,等等。因此,格式字符串在运行时或多或少会自动替换为另一个,具体取决于当前的本地化设置;它不是硬编码的,而是存在于某种数据库中。出于所有意图和目的,假设格式字符串始终是一个变量,而不是字符串文字。
所以,你所拥有的本质上是
formatstring.format(**locals())
而且你不能轻易地检查格式将使用的什么本地名称。您必须打开并仔细阅读 L10N 数据库,确定将在不同设置中使用的格式字符串,并验证所有这些。
所以在实践中,您不知道将使用哪些本地名称——这严重影响了函数的维护。你不敢重命名或删除任何局部变量,因为它可能会严重破坏具有某些(对你而言)语言、区域设置和偏好的模糊组合的用户的用户体验
如果您有出色的集成/回归测试,那么问题将在 Beta 版发布之前被发现——但 QA 会向您大喊大叫,发布将被延迟……老实说,同时以 100% 的覆盖率为目标unit 测试是合理的,它真的不是 integration 测试,一旦你考虑设置的组合爆炸 [[for L10N 和更多原因]] 并支持所有依赖项的版本。因此,您只是不要冒着损坏的风险四处走动,因为“他们会在 QA 中被抓住”(如果这样做,您可能不会在开发大型应用程序或可重用组件的环境中持续很长时间;-)。
因此,在实践中,您永远不会删除“name”局部变量,即使用户体验人员早就将该问候语切换为更合适的“欢迎,恐惧霸主!” (以及适当的 L10n'ed 版本)。都是因为你选择了locals()...
因此,由于您削弱了维护和编辑代码的能力,因此您正在积累垃圾——也许“名称”局部变量仅存在,因为它是从数据库等中获取的,所以保持它(或其他一些本地)不仅是杂乱无章的,它也会降低你的表现。 locals() 的表面便利值得那个吗?-)
但是等等,还有更糟的!在许多有用的服务中,类似lint 的程序(例如,pylint)可以为您提供警告,即警告您未使用的局部变量(希望它也可以为未使用的全局变量执行此操作,但是,对于可重复使用的组件,这有点太难了;-)。通过这种方式,您可以非常快速且廉价地发现大多数偶尔出现的拼写错误,例如 if ...: nmae = ...,而不是通过查看单元测试中断并进行侦探工作来找出 为什么 它会中断(您 确实有强迫性的、普遍的单元测试会最终捕捉到这一点,对吗?-) -- lint 会告诉你一个未使用的局部变量nmae,你会立即修复它。
但是如果你的代码中有一个blah.format(**locals()),或者等效的一个blah % locals()...你是SOL,朋友!-) 可怜的lint 怎么知道nmae 是否实际上是一个未使用的变量,或者实际上它确实被您将locals() 传递给的任何外部函数或方法使用?它不能——要么它无论如何都会发出警告(导致最终导致你忽略或禁用此类警告的“哭狼”效果),或者它永远不会发出警告(具有相同的最终效果:没有警告;-) .
将此与“显式优于隐式”的替代方案进行比较...:
blah.format(name=name)
那里——不再需要维护、性能和 am-I-hampering-lint 问题;幸福!您立即让所有相关人员(包括 lint)清楚地了解正在使用的什么局部变量,以及具体用于什么目的。
我可以继续,但我认为这篇文章已经很长了;-)。
所以,总结一下:“γνῶθι σεαυτόν!”嗯,我的意思是,“认识你自己!”。而“你自己”实际上是指“你的代码的目的和范围”。如果它是 1-off-or-thereabouts,永远不会成为 i18n'd 和 L10n'd,几乎不需要未来维护,永远不会在更广泛的环境中重复使用,等等,然后继续使用 @987654339 @ 小而整洁的便利;如果您不知道,或者即使您不完全确定,请谨慎行事,并让事情更明确 - 忍受一点点的不便,因为您要准确地说明您要做什么,并享受所有由此产生的优势。
顺便说一句,这只是 Python 努力支持“小型、一次性、探索性、也许是交互式”编程的示例之一(通过允许和支持远远超出 locals() 的风险便利——想想import *、eval、exec,以及其他几种可以混合命名空间和风险维护影响的方法),以及“大型、可重用、企业级”应用程序和组件。它可以在这两个方面做得很好,但前提是您“了解自己”并避免使用“方便”部分,除非您绝对确定您实际上可以负担得起。通常情况下,关键考虑因素是“这对我的命名空间有什么影响,以及编译器、lint &c、人类读者和维护者等对它们的形成和使用的认识?”。
请记住,“命名空间是一个很棒的主意——让我们做更多这样的事!”这就是 Python 之禅的结论......但是 Python 作为“成年人同意的语言”,允许您根据您的开发环境、目标和实践。负责任地使用这种力量!-)