Pythonic 函数重载?
Posted
技术标签:
【中文标题】Pythonic 函数重载?【英文标题】:Pythonic function overloading? 【发布时间】:2022-01-23 23:55:54 【问题描述】:我无法理解干净的方式来做到这一点。我想要一个名为set_delay()
的函数,它接受各种参数。我有 3 种不同的“延迟类型”可以设置:恒定、统一和正常。这是我目前拥有的:
def set_delay_constant(delay):
continue
def set_delay_uniform(min_delay, max_delay):
continue
def set_delay_normal(mean, std_dev, timeout):
continue
我遇到的问题是每个函数中大约 80% 的代码是重复的。我看到的想法是:
def set_delay(delay_type, delay=None, min_delay=None, max_delay=None, mean=None, std_dev=None, timeout=None):
continue
但是当我需要使用更多延迟类型来扩展它时,我可以看到它变得非常长并且难以阅读。最“pythonic”的方法是什么?谢谢!
【问题讨论】:
该代码无效...SyntaxError: 'continue' not properly in loop
。您的意思是 pass
而不是 continue
?
您可以使用keyword parameters。
@wjandrea 是的,只是作为仅包含函数头的一种方式
我认为三个单独的函数是正确的方法。您可以将公共部分分解为三个函数中的每一个调用的单个函数。
@chepner 我刚刚发布了一个答案。感谢您向我保证我走在正确的轨道上 :) 如果您对您的经验有任何补充,我将不胜感激。
【参考方案1】:
不要使用重载。您要解决的问题是“每个函数中大约有 80% 的代码被重复”,更好的解决方案是将代码分解到自己的函数中,称之为 @例如 987654322@,然后从每个 set_delay_*
函数中调用它。
对我来说,重载只在参数重叠的地方才有意义,但在你的情况下没有。相比之下,假设我写了range(10)
,但后来我意识到我想从 1 开始;由于重载,我可以简单地将其更改为range(1, 10)
。同时,如果我在您提议的set_delay
中添加一个论据,我会得到完全不同的行为。
【讨论】:
好吧,严格来说,Python 没有重载。但你的答案是关键问题 @juanpa 我想我的术语可能有点不对劲,但你到底是什么意思?如果不重载,你怎么称呼range
示例?我读到了multiple dispatch,但这似乎只是关于参数类型,而不是参数数量。
@wjandrea 就像在 Java 中一样,您可以定义多个具有相同 name 但签名不同的函数,并且调用的实际函数取决于提供给函数的参数 (通常在编译时决定)。所以看看这个C++ example on wikipedia。 Python 不支持,我不确定是否有任何动态语言支持它。但通常,只提供一个非常灵活的函数签名并自己手动实现调度是您在 Python 中经常要做的事情。
我认为 range
保留其 API尽管存在缺点,因为它的历史悠久。如果它是今天推出的,我怀疑它将有两个必需的位置参数,还有一个可选的第三个参数来指定步长。它还可能更广泛地使用仅限关键字的参数。
比较 range
到 enumerate
: range(10)
仍然可以是数字 0 到 9,range(10, start=5)
是数字 5 到 9(虽然能够有 5 和 10 “输出秩序”看起来很奇怪)。我不知道最好的解决方案是什么。【参考方案2】:
我个人会转向基于类的结构:
from abc import ABC, abstractmethod
class Delay(ABC):
def do_delay(self):
self._prepare_delay()
#put the 80% of overlapping code here
@abstractmethod
def _prepare_delay(self):
pass
class ConstantDelay(Delay):
def __init__(self, delay):
self.delay = delay
#custom code can go here
def _prepare_delay(self)
#more custom code here
class UniformDelay(Delay):
def __init__(self, min_delay, max_delay):
self.min_delay = min_delay
self.max_delay = max_delay
#custom code goes here
def _prepare_delay(self)
#more custom code here
#etc
那么您的 set_delay
函数将采用单个参数,即 Delay
子类的实例:
def set_delay(delay):
pass
【讨论】:
以上是关于Pythonic 函数重载?的主要内容,如果未能解决你的问题,请参考以下文章