2014-05-22 81 views
1

我对python(2.7)很陌生,并且对于什么是Pythonic最有效的方法有疑问。我的代码(A类的一部分)貌似这个(有点天真版):Python风格:嵌套与额外功能

def calc_pump_height(self): 
    for i in range(len(self.primary_)): 
     for j in range(len(self.primary_)): 
      if self.connections_[i][j].sub_kind_ in [1,4]: 
       self.calc_spec_pump_height(i,j) 

def calc_spec_pump_height(self,i,j): 
    pass 

(显然通行证将被别的东西所取代,操纵这个类的对象的属性,而不会产生一个返回值)我想问我应该怎么做:我可以避免第二个函数,并将额外的代码直接写入第一个函数,摆脱一个函数(简单比复杂更好),但创建一个重度同时嵌套函数(Flat比嵌套更好)。

我还可以建立某种形式的名单理解,以避免使用双回路,例如:

def calc_pump_height(self): 
    ra = range(len(self.primary_)) 
    [self.calc_spec_pump_height(i,j) for i,j in zip(ra, ra)] 

(我不得不如果条件进入第二个功能;这也将创建一个空 - 但我不在乎这一点,因为calc_spec_pump_height应该操纵对象,而不是返回一些有用的东西)

实质上:我遍历2D列表,测试每个对象的某个特征,然后用这个对象做些事情。

以上哪种方法是'最好的'?还是有另一种我失踪的方式?

+0

恕我直言,第二种方式看起来很干净,但它可能只是我... – Dair

+0

出于好奇,为什么你的一些属性的结束与_?在Python中,如果你试图指出某个类是私有的,那么你通常在开始时加一个下划线,而不是结尾。 – Ben

+0

@Ben:你说得对,现在我知道了。这实际上是我刚开始使用Python时写的一段代码的一部分,我正在重写它,但没有重新命名变量(最初的想法是区分本地变量和类变量)。在Python中这是(除了违反标准)冗余由于'自我'。在我的其他项目(例如:编程微控制器)它不是。) – cfrei89

回答

2

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

calc_pump_height实现了两件事:它在2D列表中查找与某些条件匹配的元素,然后计算每个元素的值。其目的是将其他两个操作组合起来,如果这对于对象的公共API来说是有意义的,但它不适用于实现或两者兼而有之。

  • 查找符合条件的元素是一个离散的步骤;这应该是一个功能。
  • 计算你的价值显然是一个不连续的步骤;这应该是一个功能。

我将实现元素匹配器作为(私有)生成器,它将测试条件作为参数,并生成所有匹配的元素。它只是数据结构的迭代器,被逻辑测试所掩盖。您可以将其封装在名为get_1_4_subkinds()的指定公用方法中,或者在您的域中更有意义的方法。该代码概括并赋予您未来实现其他条件的灵活性。另外,你的i和j是紧密结合的,所以把它们作为一个概念传递是有意义的。那么你的代码变成:

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

有趣的一点,我没有这样认为,但它肯定会在以后得到方便,谢谢!此外,您还有一点意见认为将它分开是有道理的,因为这两部分分开进行。 – cfrei89

0

你误解了“简约”:

直接写额外的代码进入第一功能,摆脱一个功能(简单比复杂好)

这并不简单。将复杂序列分解为离散的,集中的功能增加了的简单性。

有鉴于此,我会说是的,你应该更喜欢calc_spec_pump_height作为一个单独的功能。

0

您可以通过使用itertools.product产生在同一时间(itertools.product(range(len(self.primary_)), repeat=2),你在你的第二个版本中使用的zip将无法​​正常工作,它只会您ij值消除你的第一个功能一级嵌套产生相同的对,0,01,12,2

至于整体设计,你不应该,如果你不关心从你调用该函数的返回值,使用列表理解。使用显式循环时,它是你想要的循环(而不是一个计算值列表)

如果在calc_spec_pump_height中存在非常重要的代码量,则将其作为单独的方法进行使用是非常有意义的。如果它是一个或两个班轮,那么可以在calc_pump_height内联行,但是该方法的循环和条件测试可能已经足够复杂以足以证明分解算法的内部部分。

当你的编辑器中的一个屏幕太长时,你应该考虑分割一个大功能。这是关于我们可以同时记住多少细节(变量名等)的限制。另一方面,通过分解每一个小问题,你不应该浪费时间(无论是你自己的编程时间还是运行时的函数调用开销)。如果您在多个地方使用该功能,或者无法一次性保留头部整个功能的详细信息,则将该功能的一部分作为功能的一部分。

因此,除了itertools.product的(边际)改进之外,由于您提供的有关calc_spec_pump_height将执行的操作的信息有限,因此我认为您的代码已经达到了它所能达到的最佳状态!

+0

感谢您指出我的错误,并提供一些'基准'的长度功能等 – cfrei89