我需要调用未参数化的方法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中进行方法重载?
答案 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)))