6

这是一个样式约定问题。

类定义的 PEP8 约定类似于

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

所以说我想写一个模块范围的函数,它接受一些数据,处理它,然后创建一个 MyClass 的实例。

PEP8 说我的函数定义应该有 lowercase_underscore 样式名称,比如

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 并没有看到任何解决该问题的内容。

4

2 回答 2

11

根据函数的使用情况,将其变为 aclassmethod或可能更合适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
于 2013-01-25T21:19:31.807 回答
1

让我们退后一步。通常,您根本不想这样做,因此命名约定是您最不必担心的。

首先,通常情况下,您并不关心实际的类或类型是什么。这就是鸭子打字的意义所在。你不想要一个SpreadsheetColumn实例,你想要一些可以用作电子表格列的东西。它可能是 的实例,也可能是子类的实例,也可能是SpreadsheetColumn某个代理类的实例,或者是用于测试的某个模拟类的实例——不管它是什么,你都不在乎,只要它看起来和工作起来像一列。

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

所以,你的工厂函数应该被调用get_column,而不是get_SpreadsheetColumn.

当函数更像是“替代构造函数”而不是工厂时,那么 mgilson 的答案就是要走的路。See chain()and chain.from_iterable()in itertoolsfrom 一个好的标准库示例。

但请注意,这在标准库、PyPI 上的大多数流行模块等中并不常见。这是有充分理由的。通常,您可以只使用带有默认值参数、关键字参数或最坏情况的单个构造函数*args**kwargs. 如果这使得 API 对人类读者来说太混乱,或者对代码来说太模糊,那么你就需要一个替代的构造函数。否则,你不会。

有时,您确实需要一个创建具体类型对象的工厂,并且该具体类型是调用者需要了解的接口的一部分。正如我上面提到的,这在静态语言中也很少见,在 Python 中甚至更罕见,但它确实出现了。然后,您确实需要原始问题的答案。

在这种情况下,我想我会把这个函数命名为丑陋和不寻常的东西,比如get_MyClassor get_MyClass_instance。它应该立即突出,因为任何阅读我的代码的人都可能需要弄清楚为什么我明确地得到 aMyClass而不是 athing以便理解我的其余代码。

于 2013-01-26T00:35:25.133 回答