How to overload __init__ method based on argument type?
假设我有一个类,它有一个名为data的成员,这是一个列表。
我希望能够用文件名(其中包含初始化列表的数据)或实际列表初始化类。
你这样做的技巧是什么?
你只是通过查看
我可能会错过什么把戏吗?
我习惯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.). |
您可能需要
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. |
然后用
希望有帮助。快乐编码!
好的,太好了。我只是将这个示例与一个元组(不是文件名)混合在一起,但这很容易。谢谢大家。
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? |