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尽管存在缺点,因为它的历史悠久。如果它是今天推出的,我怀疑它将有两个必需的位置参数,还有一个可选的第三个参数来指定步长。它还可能更广泛地使用仅限关键字的参数。 比较 rangeenumerate: 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 函数重载?的主要内容,如果未能解决你的问题,请参考以下文章

类中的函数重载

类中的函数重载

关于C++函数重载问题

[C++]——函数的重载

C++运算符重载中 重载为类的成员函数和重载为类的友元函数 的区别是啥?

Python 没有函数重载?如何用装饰器实现函数重载?