python中的方法重载

method overloading in python

我需要调用非参数化方法first,但也需要参数化first,但它给出了一个错误。

1
2
3
4
5
6
7
8
9
10
11
>>> 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那样执行方法重载是可能的吗?


您的第二个first方法覆盖了原来的first方法。在Python中,不可能用与Java相同的方式创建重载方法。

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

1
2
3
4
5
6
class A:
    def first(self, f=None):
        if f is not None:
            print 'first met', f
        else:
            print 'first method'

用途:

1
2
3
a = A()
a.first()
a.first('something')


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

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

1
2
3
4
5
def func1(arg1, arg2=None):
    if arg2 != None:
        print"%s %s" % (arg1, arg2)
    else:
        print"%s" % (arg1)

我们称之为:

1
2
>>> func1(1, 2)
1 2

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

1
2
3
4
5
6
def func2(arg1, *args):
    if args:
        for item in args:
            print item
    else:
        print arg1

我们称之为:

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

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

1
2
3
4
5
6
def func3(arg1, **args):
    if args:
        for k, v in args.items():
            print"%s %s" % (k, v)
    else:
        print arg1

我们称之为:

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

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


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

也就是说,我真的很喜欢OO编程中的隐式动态分派,我发现它比在某种"master"first()函数中编写手动分派逻辑更干净,这种函数重复且易于扩展。

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#!/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);


如果有帮助,请检查此代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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)))


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

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

1
2
3
4
5
6
class A:
    def first(self, f=None):
        if f is None:
            print 'first method'
        else:
            print 'first met',f

在您的情况下,如果您希望根据这是否是对该方法的第一个调用来实现不同的行为,我将这样做:

1
2
3
4
5
6
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

样本输出:

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

印刷品:

1
2
first method
first met 3


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

实际上,执行您想要的操作的唯一方法是测试是否存在第二个参数:

1
2
3
4
5
6
class A:
   def first(self, f=None):
      if f is None:
         print 'first method'
      else:
         print 'first met',f

你可以更加复杂地检查f的类型,但这可能很危险,并不总是"Python式的"。(不过,应该提到的是,Python3中函数注释的一个用例是允许这种"通用编程"。)