8

问题:__init__编写直接将集合作为参数而不是解包其内容的优点和缺点是 什么?

上下文:我正在编写一个类来处理来自数据库表中多个字段的数据。我遍历一些大型(约 1 亿行)查询结果,一次将一行传递给执行处理的类。每行都作为元组(或可选地,作为字典)从数据库中检索。

讨论:假设我对三个字段感兴趣,但是传递给我的类的内容取决于查询,并且查询是由用户编写的。最基本的方法可能是以下之一:

class Direct:
    def __init__(self, names):
        self.names = names

class Simple:
    def __init__(self, names):
        self.name1 = names[0]
        self.name2 = names[1]
        self.name3 = names[2]

class Unpack:
    def __init__(self, names):
        self.name1, self.name2, self.name3 = names

以下是可能传递给新实例的一些行示例:

good = ('Simon', 'Marie', 'Kent')                 # Exactly what we want
bad1 = ('Simon', 'Marie', 'Kent', '10 Main St')   # Extra field(s) behind
bad2 = ('15', 'Simon', 'Marie', 'Kent')           # Extra field(s) in front
bad3 = ('Simon', 'Marie')                         # Forgot a field

面对上述情况时,Direct总是运行(至少到这一点)但很可能是错误的(GIGO)。它接受一个参数并完全按照给定的方式分配它,因此这可以是一个元组或任何大小的列表、一个 Null 值、一个函数引用等。这是我能想到的最快速和最肮脏的初始化方法对象,但我觉得当我给它显然不是为了处理而设计的数据时,该类应该立即抱怨。

Simplebad1正确处理,在给定时是错误bad2的,并且在给定时抛出错误bad3。能够有效地截断输入很方便,bad1但不值得出现错误bad2. 这个感觉很幼稚和不一致。

Unpack似乎是最安全的方法,因为它在所有三个“坏”情况下都会引发错误。我们要做的最后一件事就是默默地用不良信息填充我们的数据库,对吧?它直接采用元组,但允许我将其内容识别为不同的属性,而不是强迫我继续引用索引,并抱怨元组的大小是否错误。

另一方面,为什么要传递一个集合呢?因为我知道我总是想要三个字段,所以我可以定义__init__显式接受三个参数,并在将集合传递给新对象时使用 *-operator 解包:

class Explicit:
    def __init__(self, name1, name2, name3):
        self.name1 = name1
        self.name2 = name2
        self.name3 = name3

names = ('Guy', 'Rose', 'Deb')
e = Explicit(*names)

我看到的唯一区别是__init__定义有点冗长,我们提出TypeError而不是ValueError当元组大小错误时。从哲学上讲,如果我们获取一组数据(查询的一行)并检查其部分(三个字段),我们应该传递一组数据(元组)但存储其部分(三个属性)。所以Unpack会更好。

如果我想接受不确定数量的字段,而不是总是三个,我仍然可以选择直接传递元组或使用任意参数列表(*args、**kwargs)和*-operator 解包。所以我想知道,这是一个完全中性的风格决定吗?

4

1 回答 1

5

这个问题可能最好通过尝试不同的方法来回答,看看什么对您最有意义,并且最容易被阅读您的代码的其他人理解

既然我有更多经验的好处,我会问自己,我打算如何访问这些值?

当我访问此集合中的任何一个值时,我是否可能会使用同一子例程或代码段中的大部分或所有值?如果是这样,“直接”方法是一个不错的选择;它是最紧凑的,它让我将这个系列视为一个系列,直到我绝对需要注意里面的东西。

另一方面,如果我在这里使用一些值,在那里使用一些值,我不想一直记住要访问哪个索引或以字典键的形式添加详细信息,而我可以直接引用这些值使用单独命名的属性。在这种情况下,我可能会避免使用“直接”方法,这样我什至只需要考虑在第一次初始化类时有一个集合这一事实。

其余的每种方法都涉及将集合拆分为不同的属性,我认为这里明显的赢家是“显式”方法。“Simple”和“Unpack”方法共享对集合顺序的隐藏依赖,没有提供任何真正的优势。

于 2014-12-15T23:30:45.907 回答