python代码/函数布局

Python code/function layout

我正在学习Python,并试图找出构造代码的最佳方法。

假设我有一个长函数,并且想把它分解成更小的函数。在C中,我将使它成为顶级的"静态"函数(因为这是唯一的函数级别)。我可能还会转发声明,并将其放在使用它的现已缩短的函数之后。

现在是Python。在Python中,我可以选择创建一个嵌套函数。因为这个新的"内部"函数实际上只是为了可读性而分离出来的较大函数的一部分,而且只被它使用,所以听起来它应该是一个嵌套函数,但是在父函数中有这个函数会导致整个函数仍然很长,因为实际上没有代码从中移出!尤其是函数在被调用之前必须被完全编码,这意味着实际的短函数在这个伪长函数的末尾一路向下,使得可读性变得很糟糕!

在这种情况下,什么是良好的做法?


我能理解的是,你有一个很长的功能,比如:

1
2
3
4
def long_func(blah, foo, *args):
    ...
...
my_val = long_func(foo, blah, a, b, c)

你所做的是:

1
2
3
4
5
6
7
8
9
10
11
def long_func(blah, foo, *args):
    def short_func1():
        ...
    def short_func2():
        ...
    ...
    short_func1()
    short_func2()
    ...
...
my_val = long_func(foo, blah, a, b, c)

您还有很多选择,我将列出两个:

  • 把它变成一个班级

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    class SomeName(object):
        def __init__(self, blah, foo, *args):
            self.blah = blah
            self.foo = foo
            self.args = args
            self.result = None  # Might keep this for returning values or see (2)

        def short_func1(self):
            ...
        def short_func2(self):
            ...
        def run(self):  # name it as you like!
            self.short_func1()
            self.short_func2()
            return self.result  # (2) or return the last call, on you
    ...
    my_val = SomeName(foo, blah, a, b, c).run()
  • 制作另一个模块并将short_funcs放入其中。就像Flyx建议的那样。

    1
    2
    3
    4
    5
    def long_func(foo, blah, *args):
        from my_module import short_func1, short_func2

        short_func1(foo)
        short_func2(blah)

  • 如何将较小的函数放在自己的文件中,并将其导入到主函数中?你会有这样的东西:

    1
    2
    3
    4
    5
    6
    def main_func():
        from impl import a, b, c

        a()
        b()
        c()

    我认为这种方法导致了很高的可读性:您可以看到较小的函数来自何处,以防您想查看它们,导入它们是一个一行程序,并且主函数的实现是直接可见的。通过选择适当的文件名/位置,您还可以告诉用户,这些函数不适用于main_func以外的地方(您在python中也没有真实的信息)。

    顺便问一下:这个问题没有一个正确答案。


    据我所知,Python中内部函数的主要优点是它们继承了封闭函数的范围。因此,如果您需要访问主函数作用域中的变量(例如参数或局部变量),那么就需要使用内部函数。否则,做你喜欢做的和/或找到最可读的。

    编辑:也看到这个答案。


    良好的做法是保持网络复杂性较低。这实际上意味着将长函数分解成许多较小的函数。

    The complexity is measured by the number of if, while, do, for, ?:,
    catch, switch, case statements, and operators && and || (plus one) in
    the body of a constructor, method, static initializer, or instance
    initializer. It is a measure of the minimum number of possible paths
    through the source and therefore the number of required tests.
    Generally 1-4 is considered good, 5-7 ok, 8-10 consider re-factoring,
    and 11+ re-factor now !

    我建议采纳这一建议,它来自声纳,一种代码质量分析工具。重构此类代码的一个好方法是使用TDD。首先编写单元测试来覆盖当前函数的所有执行路径。之后,您可以放心地重构,单元测试将保证您不会破坏任何东西。

    另一方面,如果您的长函数只是长的,但另外已经具有低的圈复杂度,那么我认为函数是否嵌套并不重要。