将长变量重新分配为本地缩写是不好的风格?

时间:2011-06-07 04:32:53

标签: python readability naming-conventions

我更喜欢使用长标识符来保持我的代码在语义上清晰,但是在重复引用相同标识符的情况下,我希望它在当前范围内“摆脱困境”。以Python为例:

def define_many_mappings_1(self):
    self.define_bidirectional_parameter_mapping("status", "current_status")
    self.define_bidirectional_parameter_mapping("id", "unique_id")
    self.define_bidirectional_parameter_mapping("location", "coordinates")
    #etc...

让我们假设我真的想坚持使用这个长方法名称,并且这些参数总是会被硬编码。 实现1感觉不对,因为每行的大部分都被重复的字符占用。这些行通常也很长,并且当嵌套在类定义和/或try / except块中时容易超过80个字符,从而导致难看的换行。让我们尝试使用for循环:

def define_many_mappings_2(self):
    mappings = [("status", "current_status"),
                ("id", "unique_id"),
                ("location", "coordinates")]
    for mapping in mappings:
        self.define_parameter_mapping(*mapping)

我将在实现2的保护下将所有类似的迭代技术混为一谈,该技术改进了将“唯一”参数与“重复”方法名称分开。但是,我不喜欢这样做会将参数放在它们传入的方法之前,这是令人困惑的。我宁愿保留“动词后跟直接对象”的语法。

我发现自己使用以下方法作为妥协:

def define_many_mappings_3(self):
    d = self.define_bidirectional_parameter_mapping
    d("status", "current_status")
    d("id", "unique_id")
    d("location", "coordinates")

在实现3中,long方法由极短的“缩写”变量别名化。我喜欢这种方法,因为它可以立即识别为一组重复的方法调用,同时具有较少的冗余字符和更短的行。缺点是使用极短且语义不清晰的标识符“d”。

什么是最易读的解决方案?如果从本地范围内的未缩写版本明确分配“缩写变量”,那么它的使用是否可以接受?

4 个答案:

答案 0 :(得分:1)

再次拯救我们!尝试使用starmap - 这是一个简单的演示:

list(itertools.starmap(min,[(1,2),(2,2),(3,2)]))

打印

[1,2,2]

starmap是一个生成器,因此要实际调用这些方法,必须使用带有列表的生成器。

import itertools

def define_many_mappings_4(self):    
    list(itertools.starmap(
        self.define_parameter_mapping,
        [
            ("status", "current_status"),
            ("id", "unique_id"),
            ("location", "coordinates"),
        ] ))

通常情况下,我不喜欢使用虚拟列表构造来调用一系列函数,但这种安排似乎可以解决您的大多数问题。

如果define_parameter_mapping返回None,那么您可以将list替换为any,然后将进行所有函数调用,并且您不必构造该虚拟列表

答案 1 :(得分:0)

我会选择实施2,但这是一个非常接近的电话。

我认为#2和#3同样可读。想象一下,如果你有100多个映射......无论哪种方式,我都无法分辨底部的代码是什么而不滚动到顶部。在#2中,您将为数据命名;在#3中,您将为该函数命名。它基本上是一种清洗。

更改数据也是一种清洗,因为无论哪种方式,您只需添加一条与已有模式相同的模式。

如果您想要更改对数据所做的操作,则会出现差异。例如,假设您决定为您定义的每个映射添加调试消息。使用#2,您可以向循环添加语句,并且仍然可以轻松阅读。使用#3,您必须创建lambda或其他内容。 lambdas没什么问题 - 我和任何人一样喜欢Lisp - 但我想我仍然会发现#2更容易阅读和修改。

但这是一个很接近的电话,你的品味可能会有所不同。

答案 2 :(得分:0)

我认为虽然我可能会选择比d略长的标识符,但#3还不错,但通常这种类型的东西会变成数据驱动的,所以你会发现自己使用了#2的变体循环数据库查询的结果或来自配置文件的东西

答案 3 :(得分:0)

没有正确的答案,所以你会在这里得到各方的意见,但我到目前为止更愿意在我负责维护的任何代码中看到#2。

#1是冗长,重复且难以更改的(例如,您需要在每对上调用两个方法或添加日志记录 - 然后您必须更改每一行)。但这通常是代码发展的方式,而且它是一种相当熟悉且无害的模式。

<#>#3遇到与#1相同的问题,但稍微简单一点,要求基本上是一个宏,因此需要新的和稍微不熟悉的术语。

#2简单明了。它以数据形式列出您的映射,然后使用基本语言结构对它们进行迭代。要添加新映射,只需在数组中添加一行。您最终可能会从外部文件或URL加载映射,这将是一个简单的更改。要改变对它们所做的事情,你只需要改变你的for循环体(如果需要的话,它本身可以变成一个单独的函数)。

你对“动词之前的对象”#2的投诉并没有让我感到烦恼。在扫描该函数时,我基本上首先假设动词做了它应该做的事情,并专注于对象,现在它是清晰的,立即可见和可维护的。只有在遇到问题时我才会看动词,并且会立即明白它的作用。