python中的方法重载

时间:2012-03-15 18:34:58

标签: python overloading

我需要调用未参数化的方法first,但也需要参数化first,但它会出错。

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

是否可以像在Java中一样在Python中进行方法重载?

6 个答案:

答案 0 :(得分:11)

您的第二个first方法会覆盖原始的first方法。在Python中,不可能像在Java中一样创建重载方法。

但是,您可以使用可选和/或基于关键字的参数创建方法,并相应地处理这些参数。这是一个例子:

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

用法:

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

答案 1 :(得分:6)

Python不执行函数重载。这是因为它是一种松散类型的语言。相反,您可以指定未知数量的参数,并在函数逻辑中处理它们的解释。

有几种方法可以做到这一点。您可以指定特定的可选参数:

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

打电话给我们:

>>> func1(1, 2)
1 2

或者您可以指定未知数量的未命名参数(即在数组中传递的参数):

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

打电话给我们:

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

或者您可以指定未知数量的命名参数(即在字典中传递的参数):

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

打电话给我们:

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

您可以使用这些构造来产生您在重载时寻找的行为。

答案 2 :(得分:4)

通常,您只能在具有给定名称的类中定义一个方法。在你的例子中,2参数first()方法首先覆盖1参数()。如果你想要两个具有相同名称的方法,在python 3中你必须使用functools.singledispatch,并将实例方法名称映射到静态方法调度程序,Ouch!

那就是说,我真的很喜欢OO编程中的隐式动态调度,我发现它比在某种'master'first()函数中编写手动调度逻辑更加清晰,这是重复和脆弱的延伸。

挑战问题:添加另一种方法,如A.first(A arg)。

如果你尝试这样做,你可能会学到很多关于python类型系统的知识!

#!/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(self,arg):
        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 _(self,none):
        print("A.first() called");

    # def first(float f)
    @_first.register(float)
    def _(self,f):
        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);

答案 3 :(得分:0)

Python不是C ++或Java;你不能以同样的方式重载方法。

真的,做你想做的事的唯一方法是测试第二个参数的存在与否:

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

你可以更复杂并检查f的类型,但这可能是危险的,并不总是“pythonic”。 (但是,应该提到Python 3中function annotations的一个用例是允许这种“通用编程”。)

答案 4 :(得分:0)

虽然可以创建一个似乎使用重载方法的系统,但它有点涉及,而且通常不需要。

通常的习惯用法是将可能不需要的参数默认为None,如下所示:

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

在您的情况下,根据这是否是对该方法的第一次调用,您需要不同的行为,这就是我要做的:

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

和样本输出:

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

打印:

first method
first met 3

答案 5 :(得分:0)

检查此代码是否有用:

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