sobrecarga objetos metodos herencia constructores python constructor operator-overloading

python - objetos - ¿Cómo sobrecargar el método__init__ basado en el tipo de argumento?



sobrecarga de metodos en python (10)

Digamos que tengo una clase que tiene un miembro llamado datos que es una lista.

Quiero poder inicializar la clase con, por ejemplo, un nombre de archivo (que contiene datos para inicializar la lista) o con una lista real.

¿Cuál es tu técnica para hacer esto?

¿Simplemente verifica el tipo mirando __class__ ?

¿Hay algún truco que pueda faltar?

Estoy acostumbrado a C ++, donde la sobrecarga por tipo de argumento es fácil.


¿Por qué no vas más pitón?

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?


Deberías usar isinstance

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


Excelente pregunta. También he abordado este problema, y ​​aunque estoy de acuerdo en que las "fábricas" (constructores de métodos de clase) son un buen método, me gustaría sugerir otro, que también me parece muy útil:

Aquí hay una muestra (este es un método de read y no un constructor, pero la idea es la misma):

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

La idea clave aquí es usar el excelente soporte de Python para los argumentos con nombre para implementar esto. Ahora, si quiero leer los datos de un archivo, digo:

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

Y para leerlo de una cuerda digo:

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

De esta manera el usuario tiene un solo método para llamar. Manejarlo dentro, como viste, no es demasiado complejo.


Mi solución preferida es:

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.

Luego invócalo con MyClass() o MyClass([1,2,3]) .

Espero que ayude. ¡Feliz codificación!


Probablemente quieras la función incorporada isinstance :

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


Solución rápida y sucia

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

Entonces puedes llamarlo con

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


Una forma mucho mejor de obtener ''constructores alternativos'' es usar métodos de clase. Por ejemplo:

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

La razón por la que está más ordenada es que no hay dudas sobre qué tipo de tipo se espera, y no está obligado a adivinar qué pretendía hacer la persona que llama con el tipo de datos que le proporcionó. El problema con isinstance(x, basestring) es que no hay forma de que la persona que llama le diga, por ejemplo, que aunque el tipo no es un basstring, debe tratarlo como una cadena (y no otra secuencia). Y quizás la persona que llama quiera usar el mismo tipo para diferentes propósitos, algunas veces como un solo elemento y otras como una secuencia de elementos. Ser explícito elimina todas las dudas y conduce a un código más sólido y claro.


Una mejor manera sería usar isinstance y la conversión de tipos. Si te estoy entendiendo bien, quieres esto:

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


Vale genial. Acabo de juntar este ejemplo con una tupla, no con un nombre de archivo, pero eso es fácil. Gracias a todos.

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]


con python3, puede usar Implementing Multiple Dispatch with Function Annotations como Python Cookbook escribió:

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

y funciona como:

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)