【问题标题】:What is a good way to order methods in a Python class? [closed]在 Python 类中排序方法的好方法是什么? [关闭]
【发布时间】:2012-05-04 14:10:59
【问题描述】:

我想对 Python 类中的方法进行排序,但我不知道正确的顺序是什么。

当我在EclipsePyDev 中提取方法时,Eclipse 会将提取的方法置于修改后的方法之上。但这会将较低级别的细节置于较高级别的细节之前。根据Uncle Bob,我应该做相反的事情,这样我的代码读起来就像报纸的头条新闻。当我在Java 编程时,我只是听从他的建议。

Python 的最佳实践是什么?

【问题讨论】:

  • 没有最佳实践。做最有意义的事情——靠近顶部的重要内容是个好主意,而一致性通常是一件好事。 PEP-8 没有提到这一点,如果它是一成不变的,那就是它。
  • 甚至 PEP8 也并非一成不变。
  • 我通常按功能分组(get、set等)
  • 重要的是要注意方法函数的顺序可以是任意的,因为类声明只是定义它的方法函数,而不是调用它们.这允许类方法例程的源代码成功使用稍后将在清单中定义的方法函数。
  • 这怎么从来没有因为基于意见而关闭?

标签: python


【解决方案1】:

正如其他人指出的那样,没有正确的方法来订购您的方法。也许 PEP 建议会很有用,但无论如何。让我尽量客观地回答你的问题。

  • 接口优先:公共方法和 Python 魔术函数定义了类的接口。大多数时候,您和其他开发人员希望使用一个类而不是更改它。因此他们会对该类的接口感兴趣。将其放在源代码的首位可避免滚动浏览您不关心的实现细节。

  • 属性、magic methods、公共方法:很难定义这三者之间的最佳顺序,它们都是类接口的一部分。作为Ethan Furman says,在整个项目中坚持使用一个系统是最重要的。通常,人们期望__init__() 是类中最好的第一个函数,所以我在下面跟进其他魔术方法。

  • 阅读顺序:基本上,讲故事有两种方式:自下而上或自上而下。通过将高级函数放在首位,开发人员可以通过阅读前几行来粗略地了解该类。否则,必须阅读整个课程才能了解该课程,而大多数开发人员没有时间这样做。根据经验,将方法放在从其主体调用的所有方法之上。

  • 类方法和静态方法:通常,这是由上面解释的阅读顺序暗示的。普通方法可以多次调用所有方法,因此优先。类方法只能调用类方法和静态方法,然后来。静态方法不能调用类的其他方法并排在最后。

顺便说一下,这些规则中的大多数都不是特定于 Python 的。我不知道强制方法顺序的语言。

【讨论】:

  • 通常语言不强制排序。但是有些语言有共同的约定。例如。 C# StyleCop 有严格的订购规则。对于 Java,请参阅 stackoverflow.com/questions/4668218 等。
  • 类方法:这些通常用作构造函数,然后它们通常会显式调用__init__(与__new__结合)或隐式调用(通过默认构造函数),所以这是一个原因将它们与__init__ 放在一起。 (虽然我从未见过他们放置在之前 __init__。)
【解决方案2】:

没有一个正确的顺序。选择一个系统并坚持下去。我使用的是:

class SomeClass(object):

    def __magic_methods__(self):
        "magic methods first, usually in alphabetical order"

    def _private_method(self):
        "worker methods next, also in alphabetical order"

    def a_method(self):
        "then normal methods, also in alphabetical order"

【讨论】:

  • 您对静态方法、类变量和@property 修饰方法的偏好是什么?
  • @JohnMee:我把类变量放在首位;我的折叠方法隐藏了@staticmethod@classmethod@property 和任何其他@decorator 行,因此我使用该方法的类型来确定它的去向(除了属性倾向于在_private_methods 之间移动和normal_methods)。
  • 所以如果订单基本上从非常私有的“魔术”方法到私有到普通方法,这是否意味着接下来是 @classmethods (@classmethod def a_class_method(cls)) 然后是 @staticmethods (@staticmethod def a_static_method() )?至少这是我理解的政策...... (我的 IDE 不折叠任何东西,因为我不喜欢那样)
【解决方案3】:

我做了一些类似to Ethan 的事情,我在 Django 的源代码中看到了,主要区别在于“############”块 cmets 来划分区域。

例如,

class SomeClass(object):

    #################
    # Magic Methods #
    #################
    def __magic_methods__(self):
        "magic methods first"

    ##################
    # Public Methods #
    ##################
    def a_method(self):
        "then normal methods, in order of importance"

    ###################
    # Private Methods #
    ###################
    def _private_method(self):
        "then worker methods, grouped by importance or related function"

显然,这对较小的类不太有用。

【讨论】:

  • 但我可以看出它们很神奇,无论是公开的还是私有的。我本人非常不喜欢这样的cmets块;如果我想查看所有代码的列表,我可以查看折叠的代码。在与功能相关的特定方法块上方添加注释是我会做的事情,但对于这种类型的注释——这就是方法名称告诉我的。
  • 再一次,我只对较大的班级这样做。我发现很容易将魔术方法与半私有 () 和名称损坏 (_) 方法混淆。
  • 我正在编辑中删除丑陋的 #### 块时,我意识到你会故意将它们放在那里!我同意 顺序 i>,不过,这就是这个问题的意义所在。我建议从这个例子中删除####,因为它不属于问题的范围,而且你的例子是一个小类,无论如何你都不会使用####。 :-)
  • @MateenUlhaq 请参考编辑屏幕上显示的第二和第五条准则:“澄清含义而不改变它”和“始终尊重原作者”。 (请注意,这些都是无条件应用的,不考虑编辑自己的意见。)这个答案的全部和唯一的一点是显示那些丑陋的评论块;没有他们,它说的和 Ethan 的回答完全一样,而且它在这里毫无意义。你甚至承认这些块是“故意”存在的——知道这一点,你为什么还要去移除它们?
  • @M.I.Wright 我认为它超出了问题的范围。如您所见,rev2 仍然包含与 Ethan 不同的回答问题的材料,具有不同的排序(和子排序!)。尽管如此,还是回滚了。
【解决方案4】:

代码

class Bar(_Foo):
    pass

class _Foo:
    pass

引发异常,因为必须在使用类_Foo 之前对其进行定义。您也可以找到类似的函数异常引发示例:

def bar(f=_foo):
    pass

def _foo():
    pass

鉴于这些示例,通常在公共类和函数之前定义私有类和函数是有意义的。这就是为什么保持一致性并在公共方法之前定义私有方法是有意义的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-06-29
    • 1970-01-01
    • 2013-10-09
    • 1970-01-01
    • 2016-09-21
    • 1970-01-01
    • 1970-01-01
    • 2010-10-11
    相关资源
    最近更新 更多