【问题标题】:Pythonic way to reuse code inside only one function仅在一个函数中重用代码的 Pythonic 方式
【发布时间】:2013-05-31 23:18:12
【问题描述】:

我的问题是指在一个函数中组织多次需要的代码,而不是在其他地方。

假设以下用例:

class A(object):
    def __init__(self, base):
        self.base = base

    def foo(self):
        result = self.base + 2    # Should go to an extra function.
        result = result * 4
        if result > 10:
            result = result + 2   # Should go to an extra function.
        return result

    def bar(self):
        pass

foo() 中有重复的 x + 2 部分,在我的项目中是应该抽象的 20 行代码(将值添加到另一个对象的 20 个属性)。但是把这些放在哪里呢?我看到了三种方法:

(1.) 嵌套函数

class A(object):
    # ...

    def foo(self):
        def plus_two(value):
            return value + 2

        result = plus_two(self.base)
        result = result * 4
        if result > 10:
            result = plus_two(result)
        return result

    # ...

这似乎是有道理的,因为它是一个非常特定的用例,只与方法内部发生的事情有关。

但是:不能测试,嵌套函数不能从外部访问进行单元测试。我真的不想将其作为foo()部分 进行测试,因为它需要对plus_two全部 进行两次测试(对于两种情况)。在单元测试中,应该可以单独测试plus_two,并且只在foo() 中测试其正确的调用

(2.) 辅助方法

class A(object):
    # ...

    def foo(self):
        result = self.plus_two(self.base)
        result = result * 4
        if result > 10:
            result = self.plus_two(result)
        return result

    def plus_two(self, value):
        return value + 2

    # ...

但是:该方法现在并且永远不会被该类中的任何其他方法使用,也不需要访问self,因此它不应成为该类的方法。在不需要访问对象或不需要作为接口的一部分被覆盖的类中收集函数并不是 Pythonic。

(3.) 模块函数

def plus_two(value):
    return value + 2

class A(object):
    # ...

    def foo(self):
        result = plus_two(self.base)
        result = result * 4
        if result > 10:
            result = plus_two(result)
        return result

    # ...

但是:这会导致几个辅助函数脱离其非常特定的上下文,换句话说,不遵循封装。虽然这在这里似乎不是问题并且可能似乎是解决方案,但在我的项目中,这确实会使整个模块变得混乱,因为该功能通常与模块无关,但正如所说,非常具体到使用它的那个方法。换句话说:把它拆分到离它的上下文很远的地方,它使代码的可读性和pythonic更少。

还有其他方式吗,还是我应该选择这里显示的三种方式之一?

【问题讨论】:

    标签: python dry


    【解决方案1】:

    就个人而言,我认为选项 1 或 2 是最干净的。正如您所提到的,选项 3 非常具体地定义为模块函数。

    要在选项 1 或 2 之间做出选择,您需要确定能够对特定代码段进行单元测试的重要性。考虑到您已经基本回答了单元测试的重要性以及是否可以在 foo() 中进行单元测试的问题,

    我真的不想将其作为 foo() 的一部分进行测试

    那么您将需要使用选项 2 的一些变体。理想情况下,私有方法将是此处的方法,但由于 python 不支持,至少考虑将其命名为 __plus_two() 这是一个有关的相关问题Python 中的前导双下划线:What is the meaning of a single- and a double-underscore before an object name? 这是另一个与私有方法相关的问题:Why are Python's 'private' methods not actually private?

    【讨论】:

    • 进一步考虑您的建议,代替实例方法,您认为staticmethod 与实例或类无关,而是与“与类相关的东西”更合适然后? (嗯,它仍然会被放置在比它需要的更广泛的上下文中,但至少不像是模块函数那样。)
    • 静态下划线方法会是最佳选择吗?
    • 我们没有真实情况的所有上下文来知道将函数设为静态是否有意义。通常静态函数执行与类相关的某种功能,而不需要类的实例,这似乎不是这种情况。我认为最好的办法是使用双下划线,并很好地注释函数,说明其用途。
    【解决方案2】:

    我当然希望真实的例子更复杂:)

    我会说去嵌套或辅助函数。我个人会选择辅助功能,但这只是我的意见。 这当然是从你的描述中可以看出的。实际代码将为建议提供更好的基础,而不仅仅是一个随机示例。

    【讨论】:

      猜你喜欢
      • 2012-06-28
      • 2015-04-21
      • 1970-01-01
      • 1970-01-01
      • 2019-10-19
      • 1970-01-01
      • 1970-01-01
      • 2011-03-25
      • 1970-01-01
      相关资源
      最近更新 更多