2012-03-15 20 views
6

Necesito llamar al método no parametrizado first, pero también se ha parametrizado first, pero está dando un error.método de sobrecarga en python

>>> class A: 
...  def first(self): 
...    print 'first method' 
...  def first(self,f): 
...    print 'first met',f 
... 
>>> a=A() 
>>> a.first() 
Traceback (most recent call last): 
File "<stdin>", line 1, in <module> 
TypeError: first() takes exactly 2 arguments (1 given) 

¿Es posible sobrecargar el método en Python como en Java?

+1

* * Por favor heredar de objeto! Usted realmente no quiere una clase de estilo antiguo, ¿verdad? (Esto no sería un problema en Python 3, pero las instrucciones de impresión me dicen que estás usando Python 2.) –

Respuesta

9

Su segundo método first está anulando el método original first. En Python, no es posible crear métodos sobrecargados de la misma manera que en Java.

Sin embargo, puede crear métodos con argumentos opcionales y/o basados ​​en palabras clave y procesarlos en consecuencia. He aquí un ejemplo:

class A: 
    def first(self, f=None): 
     if f is not None: 
      print 'first met', f 
     else: 
      print 'first method' 

Uso:

a = A() 
a.first() 
a.first('something') 
+2

Sí. El estilo de argumento predeterminado de python es en realidad más conciso e, imo, más fácil de leer y mantener que la lista gigante de Java de métodos anulados con un número decreciente de argumentos. –

0

Python no es C++ o Java; no puede sobrecargar los métodos de la misma manera.

Realmente, la única manera de hacer lo que quiere es probar la presencia o ausencia del segundo parámetro:

class A: 
    def first(self, f=None): 
     if f is None: 
     print 'first method' 
     else: 
     print 'first met',f 

Usted puede ser aún más sofisticado y comprobar el tipo de f pero que puede ser peligroso, y no siempre es "pitónico". (Sin embargo, se debe mencionar que un caso de uso para function annotations en Python 3 es permitir este tipo de "Programación genérica").

0

Si bien es posible crear un sistema que parece usar métodos sobrecargados, es un poco involucrado, y generalmente no es necesario.

El idioma habitual es tener posiblemente no sean necesarios por defecto parámetros a None, así:

class A: 
    def first(self, f=None): 
     if f is None: 
      print 'first method' 
     else: 
      print 'first met',f 

En su caso, en el que desea un comportamiento diferente en función de si es o no es la primera llamada a ese método, esto es lo que haría:

class A: 
    def first(self): 
     print 'first method' 
     self.first = self._first 
    def _first(self, f):     # '_' is convention for private name 
     print 'first met',f 

y salida de ejemplo:

a = A() 
a.first() 
a.first(3) 

imprime:

first method 
first met 3 
5

Python no funciona sobrecarga. Esto es una consecuencia de que es un lenguaje débilmente tipado. En su lugar, puede especificar un número desconocido de argumentos y tratar su interpretación en la lógica de la función.

Hay varias formas de hacerlo. Puede especificar argumentos opcionales específicos:

def func1(arg1, arg2=None): 
    if arg2 != None: 
     print "%s %s" % (arg1, arg2) 
    else: 
     print "%s" % (arg1) 

Llamándola obtenemos:

>>> func1(1, 2) 
1 2 

o puede especificar un número indeterminado de argumentos sin nombre (es decir,argumentos que se pasan en un array):

def func2(arg1, *args): 
    if args: 
     for item in args: 
      print item 
    else: 
     print arg1 

llamándolo obtenemos:

>>> func2(1, 2, 3, 4, 5) 
2 
3 
4 
5 

o puede especificar un número indeterminado de argumentos con nombre (es decir, pasaron en un diccionario de argumentos):

def func3(arg1, **args): 
    if args: 
     for k, v in args.items(): 
      print "%s %s" % (k, v) 
    else: 
     print arg1 

llamándolo recibimos:

>>> func3(1, arg2=2, arg3=3) 
arg2 2 
arg3 3 

Puede usar estas construcciones para producir el comportamiento que estaba buscando en la sobrecarga.

+1

Su 'func1()' no se comporta como un llamado podría esperar cuando se llama como 'func1 (1, 0)' – bgporter

+0

Ah sí, buena captura. Hizo el cambio. – cjm

3

Por lo general, solo puede definir un método en una clase con un nombre dado. En su ejemplo, el método de 2 argumentos first() sobrescribió el argumento 1 first(). Si desea dos métodos con el mismo nombre, en python 3 debe usar functools.singledispatch y asignar el nombre del método de instancia a su asignador de métodos estáticos, ¡Ay!

Dicho esto, realmente me gusta implícita envío dinámico en la programación OO, y me resulta más limpio que escribir la lógica de envío manual de en una especie de 'maestro' primera función(), que es repetitivo y frágil a la extensión.

Pregunta del reto: agregue otro método como A.first (A arg).

¡Probablemente aprenderá mucho sobre el sistema de tipo python si intenta hacer esto!

#!/opt/local/bin/python3.4 

from functools import singledispatch; 

class A(object): 

    # default method handles dispatch for undefined types 
    # note reversed positional args to match single dispatch functools 
    @singledispatch 
    def _first(arg, self): 
     raise TypeError("no match for A._first(%s)" % type(arg)); 

    # adapter maps instance call to (reversed) static method call 
    def first(self, arg = None): return A._first(arg, self); 

    # def first() 
    @_first.register(type(None)) 
    def _(none, self): 
     print("A.first() called"); 

    # def first(float f) 
    @_first.register(float) 
    def _(f, self): 
     print("A.first(float %s) called" % f); 

a = A(); 
a.first();    # A.first() called 
a.first(None);   # A.first() called 
a.first(3.14);   # A.first(float 3.14) called 

class B(object): pass; 
b = B();     
try: a.first(b);  # no match for A._first(<class '__main__.B'>) 
except TypeError as ex: print(ex); 
+0

¡eres bueno! buen ejemplo – madjardi

+0

Oh, eso es * listo * :-) –

1

Comprobar si este código es útil:

from math import pi 

class Geometry: 

    def area(self,length = None,breadth = None,side = None,radius = None): 
     self.length = length 
     self.breadth = breadth 
     self.side = side 
     self.radius = radius 

     if length != None and breadth != None: 
      return length * breadth 
     elif side != None: 
      return side * side 
     else: 
      return pi * radius * radius 

obj1 = Geometry() 
print('Area of rectangle is {0}.'.format(obj1.area(length=5,breadth=4))) 
print('Area of square is {0}.'.format(obj1.area(side=5))) 
print('Area of circle is {0:.6}.'.format(obj1.area(radius=10))) 
Cuestiones relacionadas