4

免责声明:这可能是一个非常主观的问题,没有“正确”的答案,但我会感谢任何关于最佳实践和程序设计的反馈。所以这里是:

我正在编写一个将文本文件读入Text对象的库。现在可以使用文件名列表或直接使用对象列表来初始化这些Sentence。我想知道最好/最 Pythonic 的方法可能是什么,因为如果我理解正确,Python 不直接支持方法重载。

我在Scikit-Learn特征提取模块中找到的一个示例只是在初始化对象时将输入的类型作为参数传递。我假设一旦设置了这个参数,它只是在内部处理不同情况的问题:

if input == 'filename':
    # glob and read files
elif input == 'content':
    # do something else

虽然这很容易实现,但它看起来并不是一个非常优雅的解决方案。所以我想知道是否有更好的方法来处理多种类型的输入来初始化我忽略的类。

4

2 回答 2

4

一种方法是为实例化对象的不同方式创建具有不同名称的类方法:

class Text(object):
    def __init__(self, data):
        # handle data in whatever "basic" form you need

    @classmethod
    def fromFiles(cls, files):
        # process list of filenames into the form that `__init__` needs
        return cls(processed_data)

    @classmethod
    def fromSentences(cls, sentences):
        # process list of Sentence objects into the form that `__init__` needs
        return cls(processed_data)

这样,您只需创建一个“真实”或“规范”初始化方法,该方法接受您想要的任何“最小公分母”格式。专门的fromXXX方法可以预处理不同类型的输入,以将它们转换为传递给规范实例化所需的形式。这个想法是你调用从文件名中Text.fromFiles(...)创建一个,或者从句子对象中创建一个。TextText.fromSentences(...)Text

如果您只想接受几种可枚举的输入之一,也可以进行一些简单的类型检查。例如,类接受文件名(作为字符串)或文件对象并不少见。在这种情况下,你会这样做:

def __init__(self, file):
    if isinstance(file, basestring):
        # If a string filename was passed in, open the file before proceeding
        file = open(file)
    # Now you can handle file as a file object

如果您有许多不同类型的输入要处理,这将变得笨拙,但如果它是像这样相对包含的东西(例如,可用于获取该对象的对象或字符串“名称”),它可能比第一个更简单我展示的方法。

于 2013-05-01T05:22:23.200 回答
2

您可以使用鸭子打字。首先,您考虑参数是否属于 type X,如果它们引发异常,则假设它们属于 typeY等:

class Text(object):
    def __init__(self, *init_vals):
        try:
            fileobjs = [open(fname) for fname in init_vals]
        except TypeError:
            # Then we consider them as file objects.
            fileobjs = init_vals

        try:
            senteces = [parse_sentences(fobj) for fobj in fileobjs]
        except TypeError:
            # Then init_vals are Sentence objects.
            senteces = fileobjs

请注意,没有类型检查意味着该方法实际上接受实现您实际使用的接口之一的任何类型(例如file-like object、Sentence-like object 等)。

如果您想支持许多不同的类型,这种方法会变得非常繁重,但我认为这是糟糕的代码设计。接受超过 2,3,4 种类型作为初始值设定项可能会使任何使用您的类的程序员感到困惑,因为他总是不得不考虑“等待,X也接受Y了,或者它Z是否接受了Y......”。

最好将构造函数设计为只接受 2,3 个不同的接口,并为用户提供一些函数/类,允许他将一些常用类型转换为这些接口。

于 2013-05-01T05:38:17.067 回答