我的课程类似于以下内容:
# 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
的实例;但我不想在一篇文章中提出两个问题并开始讨论单身人士。
答案 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] = 14
和self.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_data
或do_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也可以)?
所演示的技术几乎是通用的(意味着它可以在几乎每种编程语言中使用)。因此,这适用于python-3.x和python-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所示,您可能根本不需要课程。相反,您可以将不同的功能组放入不同的模块或包中,以组织它们。