在 Python 中创建子类与传递多个参数来指定函数的变体 [英] Creating subclasses vs. passing multiple arguments to specify variants of a function in Python

查看:63
本文介绍了在 Python 中创建子类与传递多个参数来指定函数的变体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

之前问过关于组合多个相似的函数(约 10 个变体)具有大量重复或相似的代码,使其变得更简洁和面向对象.接下来,我创建了一个中心类,它的方法具有足够的灵活性,可以在给定正确参数的情况下置换到我需要的大多数函数中:

类ThingDoer:def __init__(self, settings):# 设置一些属性...def do_first_thing(self, args):same_code_1类似代码_1(参数)def do_other_thing(self, otherargs):类似代码 2(参数)same_code_2def generate_output(self):相同的代码返回 some_output

实际的东西当然更长,有更多不同的argsotherargs

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

def do_things(name, settings, args, otherargs):名称 = ThingDoer(设置)name.do_first_thing(args)name.do_second_thing(otherargs)返回 name.generate_output()

我的问题是如何处理众多变体.我看到的两个明显选项是 1) 为每个变体指定不同的选项字典,它被传递给单个 do_things 函数,或者 2) 具有 ThingDoer 的不同子类对于每个提前处理一些不同 argsotherargs 并让 do_things 使用指定为参数的所需子类的变体.>

选项 1:

# 设置参数设置字典option_1 = {args: args1, otherargs: otherargs1 ...}option_2 = {args: args2, otherargs: otherargs2 ...}...# 然后通过适当的字典调用单个函数do_things(名称,设置,**选项)

选项 2:

# 为每个变体设置子类类ThingDoer1(ThingDoer):def __init__(self):super().__init__()self.do_first_thing(args1)self.do_other_thing(otherargs1)类ThingDoer2(ThingDoer):def __init__(self):super().__init__()self.do_first_thing(args2)self.do_other_thing(otherargs2)...# 然后调用传递特定子类使用的单个函数(函数将在上面稍作修改)do_things(名称,子类,设置)

当然还有其他选择.

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

解决方案

你必须问自己的问题是:

  1. 谁将使用此代码?
  2. 谁将维护不同变体的不同代码?

我们经历了一个类似的过程来处理多个不同的设备.维护特定于变体的代码的程序员也是该库的主要用户.

由于工作重点,我们没有在需要之前充实设备特定的代码.

我们决定使用类层次结构.

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

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

如果功能是新的,那么我们将它添加到我们当时正在处理的任何设备模型的基类中,如果测试失败并且他们需要新功能,则修改旧设备的子类的更改.

I previously asked about combining multiple similar functions (~10 variants) with lots of repeated or similar code into something more concise and OO. Following up on that, I've created a central class whose methods have enough flexibility to permute into most of the functions I need given the right arguments:

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

The actual thing is rather longer of course, with more different sets of args and otherargs etc.

I then use this class in a relatively clean function to get my 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()

My question is how to handle the many variants. Two obvious options I see are 1) have a dictionary of options specified differently for each variant, which gets passed to the single do_things function, or 2) have different subclasses of ThingDoer for each variant which process some of the different args and otherargs ahead of time and have do_things use the desired subclass specified as an argument.

Option 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)

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)

There are other options too of course.

Which of these (or something else entirely) would be the best way to handle the situation? and why?

解决方案

The questions you have to ask yourself are:

  1. Who will be using this code?
  2. Who will be maintaining the divergent code for different variants?

We went through a similar process for dealing with multiple different devices. The programmer maintaining the variant-specific code was also the primary user of this library.

Because of work priorities we did not flesh out device-specific code until it was needed.

We settled on using a class hierarchy.

We built a superclass modeled on the first device variant we built code to address a particular piece of functionality and wrapped this in automated testing.

When we extended functionality to a new device that did not pass testing with existing code, we created overriding, modified methods in the new device's subclass to address failures.

If the functionality was new, then we added it to the base class for whatever device model we were working on at the time and retrofitted changes to subclasses for old devices if testing failed and they needed the new functionality.

这篇关于在 Python 中创建子类与传递多个参数来指定函数的变体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆