"overload" 在 python 中发挥作用的最佳方式?
Best way to "overload" function in python?
我正在尝试在 python 中做这样的事情:
def foo(x, y):
# do something at position (x, y)
def foo(pos):
foo(pos.x, pos.y)
所以我想根据我提供的参数数量调用不同版本的foo。这当然不行,因为我重新定义了 foo
.
实现此目标的最优雅方法是什么?我不想使用命名参数。
设置默认值的一种方法:
def foo(x, y=None):
# now for example, you can call foo(1) and foo(1,2)
在 foo
中你可以检查是否 y == None
并且对这两种情况有不同的逻辑。
请注意,如果您将功能分开,您可以有更好的设计,不要试图拥有同时接受坐标和位置的相同功能。
您尝试实现的设计看起来很糟糕,也许可以考虑坚持使用不同的函数名称:
def do_something_by_coordinates(x, y):
pass
def do_something_by_position(pos):
do_something_by_coordinates(pos.x, pos.y)
或者如果确实需要,您可以使用 kwargs
:
Understanding kwargs in Python
通常你要么定义两个不同的函数,要么做类似的事情:
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 的 foo
版本,但也为用户提供类型:
Pos = collections.namedtuple('Pos', 'x y')
那么任何会写 foo(x,y)
的人都可以写 foo(Pos(x,y))
。自然会有轻微的性能成本,因为必须创建一个对象。
您可以使用默认参数,但如果您想在 python 中使用重载,最好的方法是:
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,其中包含装饰器,如重载。如果放在method上,所有重载的方法都会调用这个方法..
您可以做很多事情,比如命名默认参数。
但是,看起来您想要的是 "multiple dispatch" 并且有许多装饰器实现可以帮助您完成这类事情。这是 one implementation,看起来像:
>>> 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 即将成为 Python 3.4,但我认为这对您的示例不起作用,因为在一种情况下您有多个参数。
我正在尝试在 python 中做这样的事情:
def foo(x, y):
# do something at position (x, y)
def foo(pos):
foo(pos.x, pos.y)
所以我想根据我提供的参数数量调用不同版本的foo。这当然不行,因为我重新定义了 foo
.
实现此目标的最优雅方法是什么?我不想使用命名参数。
设置默认值的一种方法:
def foo(x, y=None):
# now for example, you can call foo(1) and foo(1,2)
在 foo
中你可以检查是否 y == None
并且对这两种情况有不同的逻辑。
请注意,如果您将功能分开,您可以有更好的设计,不要试图拥有同时接受坐标和位置的相同功能。
您尝试实现的设计看起来很糟糕,也许可以考虑坚持使用不同的函数名称:
def do_something_by_coordinates(x, y):
pass
def do_something_by_position(pos):
do_something_by_coordinates(pos.x, pos.y)
或者如果确实需要,您可以使用 kwargs
:
Understanding kwargs in Python
通常你要么定义两个不同的函数,要么做类似的事情:
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 的 foo
版本,但也为用户提供类型:
Pos = collections.namedtuple('Pos', 'x y')
那么任何会写 foo(x,y)
的人都可以写 foo(Pos(x,y))
。自然会有轻微的性能成本,因为必须创建一个对象。
您可以使用默认参数,但如果您想在 python 中使用重载,最好的方法是:
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,其中包含装饰器,如重载。如果放在method上,所有重载的方法都会调用这个方法..
您可以做很多事情,比如命名默认参数。
但是,看起来您想要的是 "multiple dispatch" 并且有许多装饰器实现可以帮助您完成这类事情。这是 one implementation,看起来像:
>>> 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 即将成为 Python 3.4,但我认为这对您的示例不起作用,因为在一种情况下您有多个参数。