CapWords 规范:get_MyClass 还是 get_my_class

6 投票
2 回答
24339 浏览
提问于 2025-04-17 13:42

这是一个关于代码风格的问题。

根据PEP8的规定,定义一个类的方式应该像这样:

class MyClass(object):
    def __init__(self, attri):
        self.attri = attri

假设我想写一个模块级的函数,这个函数接收一些数据,处理这些数据,然后创建一个MyClass的实例。

PEP8建议我的函数名称应该使用小写字母加下划线的风格,比如:

def get_my_class(arg1, arg2, arg3):
    pass

但我倾向于用一种更清晰的方式来表明我在说的是MyClass的实例,比如这样:

def get_MyClass(arg1, arg2, arg3):
    pass

在这种情况下,my_class和MyClass之间的关系显而易见,但有些情况下就不那么明显了。比如,我从一个电子表格中提取数据,并且有一个SpreadsheetColumn类,它包含一个标题属性和一个数据列表属性。然而,如果你不知道我在说的是SpreadsheetColumn类的实例,你可能会认为我在说的是Excel表格中原始的单元格列。

我在想,是否合理违反PEP8的规定,使用get_MyClass这个命名。作为一个Python新手,我不想养成不好的命名习惯。

我查阅了PEP8和Stack Overflow,但没有找到相关的讨论。

2 个回答

1

先稍微停一下。通常情况下,你根本不想这样做,所以命名规则其实不是你最担心的事情。

首先,通常你并不在乎某个东西到底是什么具体的类或类型。这就是“鸭子类型”的意思。你并不想要一个 SpreadsheetColumn 的实例,你想要的是一个可以用作电子表格列的东西。它可以是 SpreadsheetColumn 的实例,也可以是它的子类,或者是某个代理类,甚至是用于测试的模拟类——不管是什么,只要它看起来和工作起来像一列就行。

注意,即使在像 Java 和 C# 这样的静态语言中,工厂函数(或对象)通常也不会创建一个特定的 的实例,而是创建一个 实现了特定接口的任何类 的实例。在 Python 中,这通常是隐含的。(如果不是,那通常是因为你在使用像 PEAK 或 Twisted 这样的东西,这时你应该遵循它们的协议或接口的编码风格。)

所以,你的工厂函数应该叫 get_column,而不是 get_SpreadsheetColumn

当这个函数更像是一个“替代构造函数”而不是工厂时,mgilson 的回答就是正确的方向。可以看看 chain()chain.from_iterable() 在标准库 itertools 中的例子。

但要注意,这在标准库中并不常见,大多数流行的 PyPI 模块等也是如此。这是有原因的。通常,你只需要使用一个带有默认参数、关键字参数的单一构造函数,或者在最坏的情况下使用 *args**kwargs。如果这样会让 API 对人类读者来说太混乱,或者对编码来说太模糊,那时候你才需要一个替代构造函数。否则,你就不需要。

有时候,你确实 需要 一个工厂来创建具体类型的对象,而这个具体类型是调用者需要了解的接口的一部分。正如我之前提到的,这在静态语言中都很少见,在 Python 中更是罕见,但确实会出现。然后,你真的需要对你最初问题的回答。

在这种情况下,我觉得我 给这个函数起个丑陋而不寻常的名字,比如 get_MyClassget_MyClass_instance。这样一来,它应该会立刻引起注意,因为任何阅读我代码的人可能都需要弄清楚为什么我明确要获取一个 MyClass 而不是一个 thing,以便理解我代码的其余部分。

11

根据这个函数的使用情况,把它改成一个 classmethod 或者 staticmethod 可能会更合适。这样一来,它和 class 的关系就很明确了,而且也不会违反任何命名规则。

比如:

class MyClass(object):
     def __init__(self,arg):
         self.arg = arg

     @classmethod
     def from_sum(cls,*args):
         return cls(sum(args))

inst = MyClass.from_sum(1,2,3,4)
print inst.arg  #10

撰写回答