Wie zu überladen __init__ Methode basierend auf Argument-Typ?

Lassen Sie uns sagen, ich habe eine Klasse, die ein Mitglied namens Daten, die eine Liste ist.

Ich möchte in der Lage sein, die Klasse mit zB einem Dateinamen (der Daten enthält, um die Liste zu initialisieren) oder mit einer aktuellen Liste zu initialisieren.

Was ist Ihre Technik dafür?

Siehst du einfach den Typ, indem __class__ ?

Gibt es einen Trick, den ich vermisse?

Ich bin an C ++ gewöhnt, wo Überlastung durch Argumentart einfach ist.

9 Solutions collect form web for “Wie zu überladen __init__ Methode basierend auf Argument-Typ?”

Eine viel schönere Art, "alternative Konstrukteure" zu bekommen, ist die Verwendung von Klassenmethoden. Zum Beispiel:

 >>> 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')] 

Der Grund dafür ist, dass es keinen Zweifel darüber gibt, welcher Typ erwartet wird, und Sie sind nicht gezwungen, zu erraten, was der Anrufer für Sie gedacht hat, um mit dem Datentyp zu tun, den Sie Ihnen gegeben haben. Das Problem mit isinstance(x, basestring) ist, dass es keine Möglichkeit für den Anrufer gibt, Ihnen zu sagen, zum Beispiel, dass, obwohl der Typ kein Basestring ist, sollten Sie es als String behandeln (und nicht eine andere Sequenz) Vielleicht möchte der Anrufer den gleichen Typ für verschiedene Zwecke verwenden, manchmal als ein einziges Item und manchmal als eine Folge von Items. Als explizit nimmt jeder Zweifel weg und führt zu mehr robusten und klareren Code.

Ausgezeichnete Frage. Ich habe dieses Problem auch angegangen, und während ich mir einverstanden bin, dass "Fabriken" (Klasse-Methoden-Konstruktoren) eine gute Methode sind, möchte ich einen anderen vorschlagen, den ich auch sehr nützlich fand:

Hier ist ein Beispiel (das ist eine read und kein Konstruktor, aber die Idee ist dasselbe):

 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 

Die wichtigste Idee ist hier ist die Verwendung von Pythons hervorragende Unterstützung für benannte Argumente, um dies zu implementieren. Nun, wenn ich die Daten aus einer Datei lesen möchte, sage ich:

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

Und um es aus einer Schnur zu lesen, sage ich:

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

Auf diese Weise hat der Benutzer nur eine einzige Methode zu rufen. Das Handeln, wie Sie sahen, ist nicht übermäßig komplex

Ein besserer Weg wäre, isinstance und Typ Umwandlung zu verwenden. Wenn ich dich recht verstehe, willst du das:

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

Schnell und schmutzig fix

 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 

Dann kannst du es anrufen

 MyData(astring) MyData(None, alist) MyData() 

Sie sollten isinstance verwenden

 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.). 

Sie wollen vermutlich die isinstance ?

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

Meine bevorzugte Lösung ist:

 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. 

Dann rufe es entweder mit MyClass() oder MyClass([1,2,3]) .

Ich hoffe, das hilft. Glückliche Codierung!

Ok, toll Ich habe dieses Beispiel nur mit einem Tupel zusammengefasst, kein Dateiname, aber das ist einfach. Danke allen

 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]

Warum gehst du noch nicht mehr pythonisch?

 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? 
Python ist die beste Programmiersprache der Welt.