Python风格:嵌套vs额外函数

Python风格:嵌套vs额外函数,python,Python,我对python(2.7)很陌生,我有一个问题,那就是什么是最具python风格的做事方式;我的代码(类的一部分)如下所示(有点幼稚的版本): (显然,pass将被其他内容替换,操作此类对象的属性,而不生成返回值) 我想问一下我应该怎么做:我可以避免使用第二个函数,直接将额外的代码写入第一个函数,去掉一个函数(简单的比复杂的好),但同时创建一个重嵌套的函数(扁平的比嵌套的好) 我还可以创建某种列表理解,以避免使用双循环,例如: def calc_pump_height(self): ra

我对python(2.7)很陌生,我有一个问题,那就是什么是最具python风格的做事方式;我的代码(类的一部分)如下所示(有点幼稚的版本):

(显然,pass将被其他内容替换,操作此类对象的属性,而不生成返回值)

我想问一下我应该怎么做:我可以避免使用第二个函数,直接将额外的代码写入第一个函数,去掉一个函数(简单的比复杂的好),但同时创建一个重嵌套的函数(扁平的比嵌套的好)

我还可以创建某种列表理解,以避免使用双循环,例如:

def calc_pump_height(self):
    ra = range(len(self.primary_))
    [self.calc_spec_pump_height(i,j) for i,j in zip(ra, ra)]
(我必须将if条件移动到第二个函数中;这也会创建一个空列表,但我不关心这一点,因为
calc\u spec\u pump\u height
应该操作对象,而不是返回有用的内容)

本质上:我在一个2D列表上迭代,测试每个对象的某个特性,然后对该对象执行一些操作


以上哪种方法是“最好的”?还是我缺少了另一种方式?

你误解了“简单”:

将额外的代码直接写入第一个函数,去掉一个函数(简单比复杂好)

这并不简单。将复杂序列分解为离散的、聚焦的函数增加了简单性


有鉴于此,我想说是的,您肯定更喜欢将
calc\u spec\u pump\u height
作为一个单独的函数。

您可以通过使用
itertools.product
同时生成
I
j
值(
itertools.product(range)(len(self.primary),repeat=2)
。您在第二个版本中使用的
zip
无法正常工作,它只会产生相同的对,
0,0
1,1
2,2
,等等

至于整体设计,如果您不关心所调用函数的返回值,则不应使用列表理解。如果需要循环,则使用显式循环(而不是计算值列表)

如果在
calc\u spec\u pump\u height
中有大量的代码,那么将其作为一个单独的方法是非常有意义的。如果它是一个一行或两行,那么可以在
calc\u pump\u height
中内联,但该方法的循环和条件测试可能已经非常复杂,足以证明将ut是算法的内部部分

当一个大函数太长而无法放在编辑器的单个屏幕上时,您通常应该考虑将其拆分。这是关于我们可以同时记住的细节(变量名等)数量的限制。另一方面,您不应该浪费时间(您自己的编程时间或运行时的函数调用开销)通过分解每个问题的每一个小部分。如果你在多个地方使用某个函数,或者如果你不能立即在头脑中记住整个函数的细节,那么就分解出该函数的一部分


因此,除了
itertools.product
的(边际)改进,以及您提供的关于
calc\u spec\u pump\u height
的有限信息之外,我认为您的代码已经达到了它所能达到的程度!

函数/方法的关键是它们应该做一件事

calc\u pump\u height
实现两件事:它在2D列表中查找符合某些条件的元素,然后为每个元素计算一个值。如果对对象的公共API有意义的话,它可以合并其他两个操作,但不能同时实现其中一个或两个

  • 找到符合条件的元素是一个离散的步骤;这应该是一个函数
  • 计算您的值显然是一个离散的步骤;这应该是一个函数
我将把元素匹配器实现为一个(私有)生成器,它将测试条件作为一个参数,并生成所有匹配的元素。它只是数据结构上的一个迭代器,被逻辑测试屏蔽。您可以将其封装在名为
get_1_4_subtypes()的命名公共方法中
或在您的领域更有意义的东西。这将使代码通用化,并使您能够灵活地在将来实现其他条件。此外,i和j紧密耦合,因此将它们作为单个概念传递是有意义的。然后,您的代码将变为:

def calc_pump_height(self):
    for subkind_indices in self.get_1_4_subkinds():
        self.calc_pump_spec_height(subkind_indices)

IMHO,第二种方法看起来更简洁,但可能只是我……出于好奇,为什么有些属性以ux结尾?在Python中,如果你想表示某个属性是该类的私有属性,通常在开头加下划线,而不是结尾。@Ben:你完全正确,我现在知道了。这实际上是p这是我第一次开始使用Python时编写的一段代码的艺术,我目前正在重写它,但还没有开始重命名变量(最初的想法是区分局部变量和类变量。在Python中,这是(除了违反标准之外)由于“自我”而冗余的。在我的其他项目中(例如:为微控制器编程)它不是。)谢谢你指出我的错误,并给出了一些函数长度的“基准”等有趣的观点,我没有这样考虑,但它肯定会在以后派上用场,谢谢!而且你还有一个观点,那就是把它分开是有意义的,因为这两部分做的事情是分开的。。。
def calc_pump_height(self):
    for subkind_indices in self.get_1_4_subkinds():
        self.calc_pump_spec_height(subkind_indices)