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

python 3: how do I create two different classes that operate on the same data?

我有一个 class 看起来像下面这样:

# 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

我想将其分成两个单独的 classes,因为它违反了 SRP。 do_foo_to_data()调用的函数与do_bar_to_data()调用的函数完全不同。然而它们必须在相同的 data.

上运行

我想出了一堆解决方案,但它们都很丑陋。有没有办法干净地做到这一点,最好是 Python 3(尽管 2.7 也可以)?

我的"solutions"最好的如下:

# 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 成员必须是 class 成员。 我只希望创建一个 Baz 的实例;但我不想一口气问两个问题 post 然后开始讨论单身人士。

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

class Foo:

    <b>def __init__(self,data):
        self.data = data</b>

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

class Bar:

    <b>def __init__(self,data):
        self.data = data</b>

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

终于回答你的问题了:

preferably in Python 3 (though 2.7 is OK too)?

展示的技术几乎是通用的(这意味着它在几乎每种编程语言中都可用)。所以这将适用于 and .

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

data = [42]

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

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

问题已解决。

您可以提取不同的功能组来分隔 mix-in classes:

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]

这依赖于 Python 的 duck-typing 行为。您应该只将 FooBar mix-in 应用于实际提供 self.data 的 class,例如 Baz class这里有。

这可能适用于某些 classes 按惯例无论如何都需要提供某些属性的情况,例如 Django 中的自定义视图 classes。但是,当此类约定尚未到位时,您可能不想引入新约定。错过文档然后在运行时有 NameErrors 太容易了。因此,让我们明确说明依赖关系,而不仅仅是记录它。如何?用 mix-in 表示 mix-ins!

class Data:
    """Mixin class"""
    data = [42]

class Foo(Data):
    """Mixin class"""
    def do_foo_to_data(self):
        # call a dozen functions that do complicated stuff to data

class Bar(Data):
    """Mixin class"""
    def do_bar_to_data(self):
        # call other functions that do different stuff to data

class Baz(Foo, Baz):
    pass

这是否适合您的 use-case 在这个抽象层次上很难说。正如 所示,您可能根本不需要 classes。相反,您可以将不同的功能组放入不同的模块或包中,以组织它们。