python 3:如何创建两个对同一数据进行操作的不同类?

时间:2017-01-27 21:18:54

标签: python oop single-responsibility-principle

我的课程类似于以下内容:

# Class violates the Single Responsibility Principle
class Baz:
    data = [42]
    def do_foo_to_data(self):
        # call a dozen functions that do complicated stuff to data

    def do_bar_to_data(self):
        # call other functions that do different stuff to data

我想将它分成两个单独的类,因为它违反了SRP。 do_foo_to_data()调用的函数与do_bar_to_data()调用的函数完全不同。但它们必须在同一data上运作。

我想出了一堆解决方案,但它们都很难看。有没有办法干净利落地完成,最好是在Python 3中(虽然2.7也可以)?

我最好的“解决方案”如下:

# I find this hard to read and understand
class Baz:
    data = [42]

    def create_foo(self):
        return Baz.Foo()

    def create_bar(self):
        return Baz.Bar()


    class Foo:
        def do_foo_to_data(self):
            # call foo functions


    class Bar:
        def do_bar_to_data(self):
            # call bar functions

注意:data成员是班级成员,对我来说至关重要。 我只希望创建一个Baz的实例;但我不想在一篇文章中提出两个问题并开始讨论单身人士。

3 个答案:

答案 0 :(得分:4)

这不是一个优雅的解决方案。您最好将引用传递给您希望它们操作的对象。如下所示:

class Foo:

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

    def do_foo_to_data(self):
        #...
        self.data[0] = 14
        pass

class Bar:

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

    def do_bar_to_data(self):
        #...
        self.data.append(15)
        pass

(我添加了self.data[0] = 14self.data.append(15)

之类的示例操作

现在你构建数据了。例如:

data = [42]

接下来,您构建一个Foo和一个Bar以及传递对data 的引用,如:

foo = Foo(data)
bar = Bar(data)

__init__是大多数编程语言所称的构造函数,正如您在第一个片段中看到的那样,它需要一个额外的参数data(在这种情况下,它是一个引用我们构造的data)。

然后你可以打电话:

foo.do_foo_to_data()

data设置为[14]

bar.do_bar_to_data()

将导致data等于[14,15]

请注意无法陈述 self.data = ['a','new','list']do_foo_to_datado_bar_to_data中的等效内容,因为会改变对新对象的引用。相反,您可以在列表中添加.clear(),并将新元素添加到其中,如:

def do_foo_to_data(self): #alternative version
    #...
    self.data.clear()
    self.data.append('a')
    self.data.append('new')
    self.data.append('list')

最后回答你的评论:

  

最好是在Python 3中(虽然2.7也可以)?

所演示的技术几乎是通用的(意味着它可以在几乎每种编程语言中使用)。因此,这适用于

答案 1 :(得分:4)

为什么你甚至需要上课呢?你想要的只是两个独立的函数,它们可以对某些数据做一些工作。

data = [42]

def foo(data):
    data.append('sample operation foo')

def bar(data):
    data.append('sample operation bar')

问题解决了。

答案 2 :(得分:1)

您可以提取不同的功能组来分隔混合类:

%d

这依赖于Python的鸭子打字行为。您应该只将class Foo: """Mixin class. Requires self.data (must be provided by classes extending this class). """ def do_foo_to_data(self): # call a dozen functions that do complicated stuff to data class Bar: """Mixin class. Requires self.data (must be provided by classes extending this class). """ def do_bar_to_data(self): # call other functions that do different stuff to data class Baz(Foo, Baz): data = [42] Foo混合应用于实际提供Bar的类,就像这里的self.data类一样。

这可能适用于需要提供某些属性的某些类,例如Django中的自定义视图类。但是,如果这些惯例尚未到位,您可能不想引入新的约定。很容易错过文档,然后在运行时Baz。因此,让我们明确依赖,而不是仅记录它。怎么样?混合使用混合!

NameError

在这个抽象层次上很难说这是否适合您的用例。正如RayLuo's answer所示,您可能根本不需要课程。相反,您可以将不同的功能组放入不同的模块或包中,以组织它们。