我发现了这种模式(或反模式),对此我感到非常满意。
我觉得它非常敏捷:
def example():
age = ...
name = ...
print "hello %(name)s you are %(age)s years old" % locals()
有时我用它的表弟:
def example2(obj):
print "The file at %(path)s has %(length)s bytes" % obj.__dict__
我不需要创建人为的元组并计算参数并将%s匹配位置保留在元组中。
你喜欢它吗?您会/会使用它吗?是/否,请解释。
对于小型应用程序和所谓的“一次性”脚本,这是可以的,尤其是vars
@ .format
kaizer.se提到的增强功能和@RedGlyph提到的版本。
但是,对于维护寿命长且维护人员众多的大型应用程序,这种做法会导致维护麻烦,而我认为这就是@
S.Lott的答案。让我解释一下其中涉及的一些问题,因为对于没有开发和维护大型应用程序(或此类野兽的可重用组件)的人来说,问题可能并不明显。
在“严肃的”应用程序中,您不会对格式字符串进行硬编码-或者,如果有的话,它将采用某种格式,例如_('Hello {name}.')
,其中gettext_
来自gettext或类似的i18n
/ L10n框架。关键是这样的应用程序(或可能在此类应用程序中使用的可重用模块)必须支持国际化(AKA i18n)和本地化(AKA
L10n):您希望您的应用程序能够在某些情况下发出“ Hello Paul”国家和文化,还有“ Hola Paul”,还有“ Ciao
Paul”,依此类推。因此,取决于当前的本地化设置,格式字符串在运行时会或多或少地自动被另一个替换。而不是硬编码,它存在于某种数据库中。出于所有目的和目的,请想象格式字符串始终是变量,而不是字符串文字。
因此,您所拥有的基本上是
formatstring.format(**locals())
你不能平凡检查究竟 是什么
地方的名字的格式将被使用。您必须打开并仔细阅读L10N数据库,在不同的设置中标识将在此处使用的格式字符串,并验证所有这些格式字符串。
因此,在实践中,您不 知道 将使用哪些本地名称-
这严重限制了该功能的维护。您不敢重命名或删除任何局部变量,因为这可能会严重破坏某些(对您)语言,区域设置和首选项组合的用户的用户体验
如果您进行了出色的集成/回归测试,那么在Beta版本发布之前就会发现破损-
但是质量检查将对您大喊大叫,并且版本发布会延迟…而且,老实说,我们的目标是100%覆盖 单元
测试是合理的,一旦考虑了设置的组合爆炸([出于L10N和更多原因])以及所有依赖项的受支持版本, 集成
测试实际上就不对了。因此,您只是不会轻易地冒着遭受破坏的风险,因为“它们会陷入质量检查中”(如果这样做,您可能不会在开发大型应用程序或可重用组件的环境中持续很长时间;-)。
因此,实际上,即使“用户体验”用户早已将问候语切换为更合适的“欢迎,恐惧霸王”,您也永远不会删除“名称”局部变量。(以及适当的L10n版本)。都是因为你去locals()
…
因此,由于您削弱了维护和编辑代码的能力的方式,您正在积累工作量-
也许“名称”局部变量仅存在是因为它是从数据库等中获取的,因此请保留它(或其他一些本地人不仅在工作,而且也在降低您的表现。是表面上的便利locals()
价值
是 - ?)
但是,等等,更糟的是!在许多有用的服务中,lint
类似程序(例如pylint)可以为您提供警告,警告您未使用的局部变量(希望它也可以对未使用的html" target="_blank">全局变量执行此操作,但是对于可重用的组件,这仅仅是有点太难了;-)。这样一来,您将if ...: nmae = ...
迅速而便宜地捕获大多数偶然的拼写错误,而不是看到单元测试中断并进行侦查工作以找出其 为何 会破译(您 确实
有强迫症,普遍存在的单元测试最终 会 抓住这种情况,对吗?-)-lint会告诉您一个未使用的局部变量nmae
,您将立即修复它。
但是,如果您的代码中包含ablah.format(**locals())
或等效的blah % locals()
…您是SOL,朋友!-)可怜的棉绒怎么知道nmae
实际上是否是未使用的变量,或者实际上它是否被任何外部函数或您要传递locals()
给的方法?它不能-
无论如何都会发出警告(导致“哭狼”效应,最终导致您忽略或禁用此类警告),或者永远不会发出警告(最终效果相同:无警告;-) 。
将此与“显式胜于隐式”替代方案进行比较…:
blah.format(name=name)
那里-维护,性能和烦人的皮毛担心都不再适用;极乐!您会立即让所有相关人员(包括棉绒;-)清楚地 知道 正在使用 什么
局部变量,以及到底是出于什么目的。
我可以继续,但是我认为这篇文章已经很长了;-)。
因此,总结一下:“ γνῶθισεαυτόν !”
嗯,我的意思是,“知道自己!”。我所说的“自己”实际上是“代码的目的和范围”。如果它是“按价出售”或“按价出售”之类的东西,那么永远都不会成为i18n’和L10n’d,几乎不需要将来的维护,也永远不会在更广泛的上下文中重复使用,等等,等等,然后继续使用locals()
它小而整洁的便利;如果您知道其他情况,或者即使您不确定,也请谨慎行事,使事情更加明确-
麻烦一点,因为您无法清楚地说明要走的路,并享受由此带来的所有优势。
顺便说一句,这仅仅是在哪里Python是努力支持“小,一次性的,探索性的,也许互动”节目(通过允许和支持是远远超出危险便利的一个例子locals()
-想到import *
,eval
,exec
,和其他几个为了方便起见,可以使用多种方法来命名空间和风险维护影响,以及“大型,可重用的企业级”应用程序和组件。它在两者上都可以做得很好,但前提是您“了解自己”并且避免使用“便利”部分,除非您绝对确定可以负担得起。通常,关键的考虑因素是:“这对我的命名空间有什么作用,以及编译器lint&c对它们的形成和使用的认识,
请记住,“命名空间是一个很棒的主意-让我们做更多的事!” 这就是Python的Zen总结的方式……但是Python作为“成年人同意的语言”, 您
可以根据开发环境,目标和实践来定义隐含的边界。负责任地使用此电源!-)
问题内容: 关于Javadoc的内容不多。(简而言之:它返回字符串的规范表示形式,从而允许使用来比较内部字符串==) 我什么时候可以使用此功能? 是否存在Javadoc中未提及的副作用,即JIT编译器或多或少的优化? 还有其他用途吗? 问题答案: 我何时会使用此函数来支持String.equals() 当你需要速度时,因为可以按引用比较字符串(==比等于快) 是否有Javadoc中未提及的副作用?
问题内容: 该方案。我在写与游戏相关的代码。在该游戏中,(同时也是一个类)具有的列表。有迹象表明,从继承其他类型的项目,例如,或。 显然,拥有我很方便。但是,当我获得玩家物品时,我唯一可以区分哪种物品的方法就是使用关键字。我确信我已经读过,依赖它是不好的做法。 在这种情况下可以使用吗?还是我应该重新考虑我的所有结构? 问题答案: 假设我正在写一些库存代码: 这样可以编译并正常工作。但是它错过了面向
问题内容: 在企业应用程序中使用MS SQL Identity是否是好的做法?在创建业务逻辑以及将数据库从一个迁移到另一个时,难道不是很困难吗? 问题答案: 是的,它们工作得很好,可靠,性能最佳。与不使用身份字段相比,使用身份字段的一大好处是它们可以处理多个调用方尝试保留新ID的所有复杂的并发问题。这看起来似乎是微不足道的代码,但事实并非如此。 以下这些链接提供了一些有关身份字段以及为什么应尽可能
问题内容: 我有一个枚举: 使用方法检查枚举成员之间的“层次结构” 是否存在问题?我的意思是-使用它时,除了冗长之外,还有什么缺点吗?将来有人可能会意外更改顺序。 还是做这样的事更好: 问题答案: TLDR:不,您不应该! 如果您参考javadoc中的方法: 大多数程序员都不会使用这种方法。它设计用于复杂的基于枚举的数据结构,例如和。 首先-阅读手册(在这种情况下为javadoc)。 其次-不要编
问题内容: 我知道关键字存在于Java中。但是我不记得看到使用它的代码。可能我正在使用异常,并在本可以使用的地方登录。在Java中使用关键字是否是一种好习惯? 编辑 :我知道断言通常是一个好习惯。我的问题是,更准确地说,如果在Java中断言的BKM是使用关键字而不是使用异常,日志记录和其他技术。 问题答案: 不使用断言的主要原因是因为默认情况下未启用断言。因此,如果您的条件足够重要而需要断言,则不
问题内容: 我设法定义一个类A,使用另一个类B的实例列表作为类A的实例变量。B类具有更改A类的另一个实例变量a1的功能。类A还具有更改类B的实例变量bb的功能。因此,A类可以访问B类,而B类可以访问A类。这两个类嵌套在一起。我知道我们可以简化将B类的所有实例变量和函数更改为A类的事情。但是在我的项目中,这种嵌套结构才是真正的东西。 我想知道的是,这种嵌套类是否会降低python的效率?有更好的解决