关于python:如何基于参数类型重载 __init__方法?

How to overload __init__ method based on argument type?

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

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

你这样做的技巧是什么?

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

我可能会错过什么把戏吗?

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


获得"备用构造函数"的一个更简洁的方法是使用ClassMethods。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
>>> 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
'
, 'bar
'
, 'baz
'
]
>>> MyData.fromdict({"spam":"ham
<div class="
suo-content">[collapse title=""]<ul><li>酷!在哪里可以看到@classmethod在引擎盖下究竟做了什么?</li><li>python.org/download/releases/2.2.3/descrintro是一个很好的源代码。</li><li>您在哪里定义了cls()的行为?</li><li>@Ajay请参阅此问题以获得澄清</li><li>为什么不使用<wyn>@staticmethod</wyn>,因为本例中的<wyn>__init__</wyn>做得很漂亮,没有什么有用的,当目标是首先使用<wyn>fromfilename</wyn>时?</li><li>我为此奋斗了一段时间,最后我创建了一个基类和两个子类,每个子类都有不同的初始参数列表。这对我来说更易读。谢谢你的鼓励!</li></ul>[/collapse]</div><hr>
<p>
Excellent question. I've tackled this problem as well, and while I agree that"
factories" (class-method constructors) are a good method, I would like to suggest another, which I've also found very useful:
</p>

<p>
Here's a sample (this is a <wyn>read</wyn> method and not a constructor, but the idea is the same):
</p>

[cc lang="
python"]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对命名参数的出色支持来实现这一点。现在,如果我想从文件中读取数据,我会说:

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

要从一个字符串中读取它,我说:

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

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


快速而肮脏的修复

1
2
3
4
5
6
7
8
class MyData:
    def __init__(string=None,list=None):
        if string is not None:
            #do stuff
        elif list is not None:
            #do other stuff
        else:
            #make data empty

然后你可以打电话给

1
2
3
MyData(astring)
MyData(None, alist)
MyData()


更好的方法是使用isInstance和类型转换。如果我理解你是对的,你需要这个:

1
2
3
4
5
6
def __init__ (self, filename):
    if isinstance (filename, basestring):
        # filename is a string
    else:
        # try to convert to a list
        self.path = list (filename)


使用python3,可以像python cookbook所写的那样使用函数注释实现多个分派:

1
2
3
4
5
6
7
8
9
10
11
12
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)

它的工作原理是:

1
2
3
4
5
6
>>> d = Date(2012, 12, 21)
>>> d.year
2012
>>> e = Date()
>>> e.year
2018


你应该用IsInstance

1
2
3
4
5
6
7
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.).


您可能需要isinstance内置函数:

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


我的首选解决方案是:

1
2
3
4
5
6
class MyClass:
    _data = []
    __init__(self,data=None):
        # do init stuff
        if not data: return
        self._data = list(data) # list() copies the list, instead of pointing to it.

然后用MyClass()MyClass([1,2,3])调用它。

希望有帮助。快乐编码!


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

1
2
3
4
5
6
7
8
9
10
11
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〕


你为什么不去做更多的Python?

1
2
3
4
5
6
7
8
9
10
class AutoList:
def __init__(self, inp):
    try:                        ## Assume an opened-file...
        self.data = inp.read()
    except AttributeError:
        try:                    ## Assume an existent filename...
            with open(inp, 'r') as fd:
                self.data = fd.read()
        except:
            self.data = inp     ## Who cares what that might be?