选择对象实例化的几种方法之一

时间:2019-02-12 13:28:50

标签: python python-3.x methods

我有一个Python类,我们将其命名为MyClass,它带有几个绑定方法。我需要一种称为.dynamic_method()的方法的行为,这取决于对象创建过程中参数集的值。 dynamic_method会有少量变体,它们之间将共享很少的代码,因此将它们定义为单独的函数/方法而不是将其定义为具有许多选项和条件的单个大型方法是有意义的。创建对象后,我不需要更改此方法的行为,可以在__init__()期间进行所有设置。

作为参考,MyClass管理数据集,.dynamic_method处理此数据的某些IO方面,这些方面随数据集和上下文而变化。

这在技术上并不难实现,但是我想出的所有方法都不完全正确:

  1. 分别将方法变量定义为函数,并在__init__()期间使用此处描述的方法之一将它们之一作为绑定方法附加:Adding a Method to an Existing Object Instance。对我来说,这似乎是最自然的选择,但是该主题中的许多答案都强烈建议不要使用此模式。
  2. 在类定义中将所有可能的方法定义为.dynamic_method_a.dynamic_method_b等,并设置一个选项/别名,以便MyClass.dynamic_method()调用正确的方法。这将导致很长的类定义,并且每个对象都有许多未使用的方法。
  3. 将方法存储为单独的函数,并使.dynamic_method()仅将self作为第一个参数来调用正确的函数。感觉是对方法概念的故意滥用,会破坏掉毛。
  4. 使用工厂模式或对象生成器功能。我宁愿避免这种情况,因为它会增加代码库中最复杂的内容。

什么被认为是实现此行为的最“ Pythonic”方式?以上方法之一,还是我想念的明显替代方法?

3 个答案:

答案 0 :(得分:3)

我认为您使这个问题过于复杂了。

如果您没有重要的理由来更改method属性(第一个选项),那么我会在glControl = new GLControl(new OpenTK.Graphics.GraphicsMode(32, 24, 0, 8)); 中编写一个不错的if-else来调用其他函数(第三个选项),或者我真的很想像我要像这样dynamic_method()做一个临时的开关盒:

dict

答案 1 :(得分:1)

我建议工厂,确实会增加复杂性,但是我要指出一些优点。

  • 对未来变化的灵活性
  • 在阅读代码时,仅通过类,就更容易理解对象期望的行为
  • 如果将IDE与类型提示(pycharm或其他类型)一起使用,则由于IDE可以在运行时之前了解对象将使用哪种方法,因此编码会更容易

代码示例:

class DataStruct:

    def __init__(self, input_: str):
        self.Field = input_

class MyClass:

    def __init__(self, data: DataStruct):
        self.Data: DataStruct = data

    def dynamic_method(self):
        # Abstract Method
        pass

    def __str__(self):
        return self.Data.Field

class MyClassFunctionalityOne(MyClass):

    def __init__(self, data: DataStruct):
        super().__init__(data)

    def dynamic_method(self):
        self.Data.Field = self.Data.Field.upper()


class MyClassFunctionalityTwo(MyClass):

    def __init__(self, data: DataStruct):
        super().__init__(data)

    def dynamic_method(self):
        self.Data.Field = "and now for something completely different"


class MyClassFactory:

    def __init__(self):
        pass

    @classmethod
    def manufacture(cls, input_: DataStruct) -> MyClass:
        #replace this if..elif chain to contain the tests on the data you need for determine the right method
        if input_.Field.count('one') > 0:
            obj: MyClass = MyClassFunctionalityOne(input_)
        elif input_.Field.count('two')> 0:
            obj: MyClass = MyClassFunctionalityTwo(input_)
        else:
            obj = None

        return obj


# script starts here
received_data = DataStruct('This kind of data should result in functionality one')
object1 = MyClassFactory.manufacture(received_data)
received_data = DataStruct('This kind of data should result in functionality two')
object2 = MyClassFactory.manufacture(received_data)
print (type(object1))
print (type(object2))
print ('*'*5, 'objects before dynamic_method', '*'*5)
print (object1)
print (object2)
object1.dynamic_method()
object2.dynamic_method()
print ('*'*5, 'objects after dynamic_method', '*'*5)
print (object1)
print (object2)

输出:

<class '__main__.MyClassFunctionalityOne'>
<class '__main__.MyClassFunctionalityTwo'>
 ***** objects before dynamic_method *****
This kind of data should result in functionality one
This kind of data should result in functionality two
***** objects after dynamic_method *****
THIS KIND OF DATA SHOULD RESULT IN FUNCTIONALITY ONE
and now for something completely different

答案 2 :(得分:1)

我宁愿选择选项3,因为我发现它更干净,但这取决于您需要多少个实现变体。选项4(使用工厂)也不错,但是它将生成更多代码。另一方面,选项4更具可扩展性和可维护性。

因此,由于您想更改dynamic_method()__init__()的行为,因此可以这样做:

class MyClass(object):
     def __init__(self, param=None):
         self.dynamic_method = {
             "a": self.dynamic_a,
             "b": self.dynamic_b,
             "c": self.dynamic_c}[param]

     def dynamic_a(self):
         print("a functionality")

     def dynamic_b(self):
         print("b functionality")

     def dynamic_c(self):
         print("c functionality")

>> m = MyClass("b")
>> m.dynamic_method()
b functionality