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

2024-09-26 22:54:49 发布

您现在位置:Python中文网/ 问答频道 /正文

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

我希望能够使用文件名(其中包含用于初始化列表的数据)或实际列表来初始化该类

你做这件事的技巧是什么

你只是通过查看__class__来检查类型吗

有什么我可能错过的把戏吗

我习惯C++,其中参数类型重载很容易。


Tags: 数据类型列表技巧data参数文件名成员
3条回答

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

下面是一个示例(这是一个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")

这样,用户只需调用一个方法。正如您所看到的,在内部处理它并不太复杂

使用python3,您可以使用Python食谱中所写的Implementing Multiple Dispatch with Function Annotations

import time


class Date(metaclass=MultipleMeta):
    def __init__(self, year:int, month:int, day:int):
        self.year = year
        self.month = month
        self.day = day

    def __init__(self):
        t = time.localtime()
        self.__init__(t.tm_year, t.tm_mon, t.tm_mday)

它的工作原理如下:

>>> d = Date(2012, 12, 21)
>>> d.year
2012
>>> e = Date()
>>> e.year
2018

获取“备用构造函数”的一种更简洁的方法是使用类方法。例如:

>>> 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)的问题在于,调用者无法告诉您,例如,即使类型不是基串,您也应该将其视为字符串(而不是另一个序列)。而且调用者可能希望将同一类型用于不同的目的,有时作为单个项,有时作为项序列。明确化消除了所有疑问,并导致更健壮、更清晰的代码

相关问题 更多 >

    热门问题