在Python中创建子类与传递多个参数以指定函数的变体

在Python中创建子类与传递多个参数以指定函数的变体,python,python-3.x,function,oop,Python,Python 3.x,Function,Oop,我希望将多个类似的函数(~10个变体)与大量重复或类似的代码组合成更简洁、更面向对象的东西。接下来,我创建了一个中心类,在给定正确参数的情况下,该类的方法具有足够的灵活性,可以转换为我需要的大多数函数: class ThingDoer: def __init__(self, settings): # sets up some attrs ... def do_first_thing(self, args): identical_co

我希望将多个类似的函数(~10个变体)与大量重复或类似的代码组合成更简洁、更面向对象的东西。接下来,我创建了一个中心类,在给定正确参数的情况下,该类的方法具有足够的灵活性,可以转换为我需要的大多数函数:

class ThingDoer:
    def __init__(self, settings):
        # sets up some attrs
        ...
    def do_first_thing(self, args):
        identical_code_1
        similar_code_1(args)
    def do_other_thing(self, otherargs):
        similar_code_2(args)
        identical_code_2
    def generate_output(self):
        identical_code
        return some_output
当然,实际的事情相当长,有更多不同的
参数集
其他参数集
等等

然后,我在一个相对干净的函数中使用这个类来获得我的输出:

def do_things(name, settings, args, otherargs):
    name = ThingDoer(settings)
    name.do_first_thing(args)
    name.do_second_thing(otherargs)
    return name.generate_output()
我的问题是如何处理许多变体。我看到的两个明显的选项是:1)为每个变量指定了不同的选项字典,该字典传递给单个
do\u things
函数,或者2)对于提前处理一些不同的
arg
otherarg
的每个变量,具有不同的
ThingDoer
子类,并使用指定为参数的所需子类

备选案文1:

# Set up dictionaries of parameter settings
option_1 = {args: args1, otherargs: otherargs1 ...}
option_2 = {args: args2, otherargs: otherargs2 ...}
...

# And then call the single function passing appropriate dictionary
do_things(name, settings, **option)
备选案文2:

# Set up subclasses for each variant
class ThingDoer1(ThingDoer):
    def __init__(self):
        super().__init__()
        self.do_first_thing(args1)
        self.do_other_thing(otherargs1)

class ThingDoer2(ThingDoer):
    def __init__(self):
        super().__init__()
        self.do_first_thing(args2)
        self.do_other_thing(otherargs2)
...

# And then call the single function passing specific subclass to use (function will be modified slightly from above)
do_things(name, subclass, settings)
当然,还有其他选择


以下哪一种(或完全其他的)是处理这种情况的最佳方式?为什么呢?

你要问自己的问题是:

  • 谁将使用此代码
  • 谁将为不同的变体维护不同的代码
  • 对于处理多个不同的设备,我们也经历了类似的过程。维护变量特定代码的程序员也是该库的主要用户

    由于工作的优先性,我们在需要时才充实特定于设备的代码

    我们决定使用类层次结构

    我们以第一个设备变体为模型构建了一个超类,我们构建了代码来处理特定的功能,并将其封装在自动化测试中

    当我们将功能扩展到未通过现有代码测试的新设备时,我们在新设备的子类中创建了重写、修改的方法来解决故障


    如果功能是新的,那么我们将其添加到我们当时正在开发的任何设备模型的基类中,如果测试失败,并且旧设备需要新功能,我们将对其子类进行修改。

    一般来说,这取决于您希望向那些将使用您的API的用户公开的自定义级别。假设我们正在编写一些代码来发送HTTP请求(这只是一个示例,显然有很多库用于此)

    如果调用者只关心易于配置的值,那么使用具有正常默认值的关键字参数可能是一种方法。也就是说,您的代码可能最终看起来像:

    from typing import Dict
    
    def do_request(url: str,
                   headers: Dict[str, str],
                   timeout: float = 10.0,
                   verify_ssl: bool = False,
                   raise_on_status_error: bool = False):
        # ...
    
    do_request('https://www.google.com')
    
    如果您想公开更多定制的行为,您可能会受益于使用几个方法定义基类,这些方法可以被覆盖(或不被覆盖)以提供更具体的行为。比如说:

    class HTTPClient(object):
    
        def do_request(self, url: str, *args, **kwargs):
            self.before_request(url, *args, **kwargs)
            result = self.send(url, *args, **kwargs)
            self.after_request(result)
            return result
    
        def send(self, url: str, *args, **kwargs):
            # Same stuff as the above do_request function.
    
        def before_request(self, *args, **kwargs):
            # Subclasses can override this to do things before making a request.
            pass
    
        def after_request(self, response):
            # Subclasses can override this to do things to the result of a request.
            pass
    
    
    client = HTTPClient()
    response = client.do_request('https://www.google.com')
    
    如果需要,子类可以在请求之前和请求之后实现
    ,但默认情况下,其行为与上述等效函数相同


    希望这有帮助!如果这与您的用例不相关,请提前表示歉意。

    您能给出一个更具体的示例,说明您正试图实现的目标吗?现在的问题是,我很难知道您试图避免什么陷阱,以及您希望通过OOP澄清什么。我最初使用的变量函数基本上修改/编译了一组指令,然后将其输入特定的外部建模软件。在我的整个工作流程中,外部软件会被多次调用,使用许多不同的指令配置。因此,这些变体的存在部分是为了以不同的方式配置指令,部分是为了在整个流程的不同阶段进行工作流控制。至于我所希望的重新编码选择,我总体上试图尽量减少重复(以前的代码有很多重复),同时保持合理的可读性和易于理解。以后以最少的代码重复灵活地添加更多变体也很好。速度不那么重要,因为外部软件离瓶颈很远。