Wie __init__ Methode Argument Typ basiert, um eine Überlastung?
-
02-07-2019 - |
Frage
Lassen Sie uns sagen, dass ich eine Klasse, die ein Mitglied hat Daten genannt, die eine Liste ist.
Ich möchte in der Lage, die Klasse mit, zum Beispiel zu initialisieren, einen Dateinamen (die Daten enthält, um die Liste zu initialisieren) oder mit einer aktuellen Liste.
Was ist Ihre Technik, dies zu tun?
Kontrollieren Sie, nur die Art von an __class__
suchen?
Gibt es einen Trick, den ich fehlen könnte?
Ich bin zu C ++ verwendet, wo durch das Argument Typ Überlastung ist einfach.
Lösung
Eine viel ordentliche Art und Weise "alternative Konstrukteurs zu bekommen, ist Class zu verwenden. 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, es ordentlicheres ist, dass es keinen Zweifel ist, welche Art zu erwarten ist, und Sie sind nicht auf das, was der Anrufer soll erraten gezwungen, für Sie mit dem Datentyp tun, es Ihnen gab. Das Problem mit isinstance(x, basestring)
ist, dass es keine Möglichkeit für den Anrufer, Ihnen zu sagen, zum Beispiel, dass, obwohl der Typ kein basestring ist, können Sie es als String behandeln sollte (und nicht eine andere Sequenz.) Und vielleicht würde der Anrufer möchte die gleiche Art für verschiedene Zwecke, manchmal als ein einzelnes Element, und manchmal als eine Folge von Elementen zu verwenden. Als explizit alle Zweifel weg nimmt und führt zu robusteren und klarem Code.
Andere Tipps
Ausgezeichnete Frage. Ich habe auch dieses Problem in Angriff genommen, und während ich, dass „Fabriken“ (Klasse-Methode Bauer) vereinbaren eine gute Methode sind, würde Ich mag eine andere vorschlagen, die ich auch sehr nützlich gefunden habe:
Hier ist eine Probe (dies ist eine read
Methode und kein Konstruktor, aber die Idee ist die gleiche):
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 zentrale Idee hier ist, unter Verwendung von Python eine hervorragende Unterstützung für benannte Argumente, dies umzusetzen. Nun, wenn ich die Daten aus einer Datei lesen will, sage ich:
obj.read(filename="blob.txt")
Und es aus einem String zu lesen, sage ich:
obj.read(str="\x34\x55")
Auf diese Weise der Benutzer nur eine einzige Methode hat zu rufen. es in der Handhabung, wie Sie sahen nicht allzu komplex
quick and dirty 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 rufen Sie können es mit
MyData(astring)
MyData(None, alist)
MyData()
Eine bessere Möglichkeit wäre isinstance und Typumwandlung zu verwenden. Wenn ich Sie recht bin zu verstehen, wollen Sie diese:
def __init__ (self, filename):
if isinstance (filename, basestring):
# filename is a string
else:
# try to convert to a list
self.path = list (filename)
mit python3, können Sie Implementieren von mehreren Versand mit Funktion Anmerkungen als Python-Kochbuch schrieb:
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)
und es funktioniert wie:
>>> d = Date(2012, 12, 21)
>>> d.year
2012
>>> e = Date()
>>> e.year
2018
Sie sollten verwenden 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.).
Sie wollen wahrscheinlich die isinstance
gebautet Funktion:
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.
aufrufen Dann ist es entweder mit MyClass()
oder MyClass([1,2,3])
.
Ich hoffe, das hilft. Glücklich Coding!
OK, groß. Ich warf nur zusammen, um dieses Beispiel mit einem Tupel, keinen Dateinamen, aber das ist einfach. Vielen Dank an Alle.
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 Sie nicht einmal mehr pythonic gehen?
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?