如何根据参数类型重载__init__方法?

时间:2020-03-06 14:48:15  来源:igfitidea点击:

假设我有一个类,该类具有一个名为data的成员,该成员是一个列表。

我希望能够使用例如文件名(包含用于初始化列表的数据)或者实际列表进行初始化的类。

我们执行此操作的技巧是什么?

我们是否只是通过查看__class__来检查类型?

我可能会缺少一些技巧吗?

我习惯了C ++,按参数类型进行重载很容易。

解决方案

更好的方法是使用isinstance和类型转换。如果我对理解正确,那么我们需要这样做:

def __init__ (self, filename):
    if isinstance (filename, basestring):
        # filename is a string
    else:
        # try to convert to a list
        self.path = list (filename)

我们可能想要isinstance内置函数:

self.data = data if isinstance(data, list) else self.parse(data)

我们应该使用isinstance

isinstance(...)
    isinstance(object, class-or-type-or-tuple) -> bool

    Return whether an object is an instance of a class or of a subclass thereof.
    With a type as second argument, return whether that is the object's type.
    The form using a tuple, isinstance(x, (A, B, ...)), is a shortcut for
    isinstance(x, A) or isinstance(x, B) or ... (etc.).

好,很好。我只是将这个示例与一个元组(而不是文件名)放在一起,但这很容易。谢谢大家

class MyData:
    def __init__(self, data):
        self.myList = []
        if isinstance(data, tuple):
            for i in data:
                self.myList.append(i)
        else:
            self.myList = data

    def GetData(self):
        print self.myList

a = [1,2]

b =(2,3)

c = MyData(a)

d = MyData(b)

c.GetData()

d.GetData()

[1,2]

[2,3]

获取"替代构造函数"的一种更整洁的方法是使用类方法。例如:

>>> class MyData:
...     def __init__(self, data):
...         "Initialize MyData from a sequence"
...         self.data = data
...     
...     @classmethod
...     def fromfilename(cls, filename):
...         "Initialize MyData from a file"
...         data = open(filename).readlines()
...         return cls(data)
...     
...     @classmethod
...     def fromdict(cls, datadict):
...         "Initialize MyData from a dict's items"
...         return cls(datadict.items())
... 
>>> MyData([1, 2, 3]).data
[1, 2, 3]
>>> MyData.fromfilename("/tmp/foobar").data
['foo\n', 'bar\n', 'baz\n']
>>> MyData.fromdict({"spam": "ham"}).data
[('spam', 'ham')]

它之所以整洁,是因为毫无疑问期望使用什么类型,并且我们不必强迫猜测调用者打算使用它给数据类型做什么。 isinstance(x,basestring)`的问题在于,调用者无法告诉我们,例如,即使类型不是基本字符串,我们也应将其视为字符串(而不是其他序列)。 )并且调用者可能希望出于不同的目的使用相同的类型,有时将其用作单个项目,有时将其作为一系列项目使用。明确表示将消除所有疑问,并导致更健壮和更清晰的代码。

很好的问题。我也解决了这个问题,虽然我同意"工厂"(类方法构造函数)是一个好方法,但我想提出另一个建议,我也发现它非常有用:

这是一个示例(这是一个read方法,而不是构造函数,但想法是相同的):

def read(self, str=None, filename=None, addr=0):
    """ Read binary data and return a store object. The data
        store is also saved in the interal 'data' attribute.

        The data can either be taken from a string (str 
        argument) or a file (provide a filename, which will 
        be read in binary mode). If both are provided, the str 
        will be used. If neither is provided, an ArgumentError 
        is raised.
    """
    if str is None:
        if filename is None:
            raise ArgumentError('Please supply a string or a filename')

        file = open(filename, 'rb')
        str = file.read()
        file.close()
    ...
    ... # rest of code

这里的关键思想是利用Python对命名参数的出色支持来实现这一点。现在,如果我想从文件中读取数据,我会说:

obj.read(filename="blob.txt")

为了从字符串中读取它,我说:

obj.read(str="\x34\x55")

这样,用户只有一个方法可以调用。如我们所见,在内部处理它并不过分