Best way to “overload” function in python?
我正在尝试在python中执行类似的操作:
1 2 3 4 5 | def foo(x, y): # do something at position (x, y) def foo(pos): foo(pos.x, pos.y) |
所以我想根据我提供的参数数量调用不同版本的foo。这当然不行,因为我重新定义了
实现这一目标最优雅的方式是什么?我不喜欢使用命名参数。
可以使用默认参数,但如果希望在Python中使用重载,最好的方法是:
1 2 3 4 5 6 7 | from pytyp.spec.dispatch import overload @overload def foo(x,y): @foo.overload def foo(x, y,z): |
pytyp是一个python包(可以从https://pypi.python.org/pypi/pytyp下载)。它包括模块pytyp.spec.dispatch,其中包含诸如重载之类的装饰器。如果它在方法上,则将为所有重载方法调用此方法。
通常,您要么定义两个不同的函数,要么执行如下操作:
1 2 3 4 | def foo(x, y = None): if y is None: x, y = x.x, x.y # do something at position (x, y) |
定义两个不同函数的选项似乎很难,如果你习惯了有重载的语言,但是如果你习惯了像python或c这样的语言,那么这就是你要做的。上面的代码在Python中的主要问题是,编写第一个参数的文档有点困难,这两种情况下并不意味着相同。
另一种选择是只定义接受POS的
1 | Pos = collections.namedtuple('Pos', 'x y') |
那么,任何一个写过
您可以做很多事情,比如命名的默认参数。
但是,看起来您想要的是"多分派",并且有许多实现可以帮助您完成这类工作。下面是一个类似的实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | >>> from multipledispatch import dispatch >>> @dispatch(int, int) ... def add(x, y): ... return x + y >>> @dispatch(Position) ... def add(pos): ... return"%s + %s" % (pos.x, pos.y) >>> add(1, 2) 3 >>> pos = Position(3, 4) >>> add(pos) 7 |
虽然@functools.singledispatch将要用到python3.4,但我认为这对您的示例不起作用,因为在一个例子中,您有多个参数。
您试图实现的设计看起来很糟糕,可以考虑使用不同的函数名:
1 2 3 4 5 | def do_something_by_coordinates(x, y): pass def do_something_by_position(pos): do_something_by_coordinates(pos.x, pos.y) |
或者,如果您确实需要:了解Python中的Kwargs
一种方法是设置默认值:
1 2 | def foo(x, y=None): # now for example, you can call foo(1) and foo(1,2) |
在
请注意,如果分离函数,您可以有一个更好的设计,不要试图拥有同时接受坐标和位置的相同函数。