这可能是一个太普遍的问题,但仍困扰着我。一般来说,什么是更好的实践(以及为什么):代理或子类化基类? base 我的意思是标准类之一,通常甚至不用Python实现。
更具体的问题如下:我希望为图形边创建一个对象;图形边缘本质上是一对两个顶点。顶点可以是任何可哈希的对象。我希望边缘会暴露出比frozenset
暴露更多的方法。所以我想知道我是否应该
class Edge(frozenset):
def my_method(self, *args):
return 3
或
class Edge(object):
def __init__(self, *args):
self._frozenset = frozenset(*args)
def __len__(self):
return len(self._frozenset)
def ...
第一种方法的好处是我必须少写(因为我不必复制所有原始方法)。然而,第二种方法在某种意义上看起来更安全。它也更灵活,因为它允许我避免使用frozenset
暴露的一些方法(例如difference
),如果我愿意的话。
第一种方法还引入了传递的参数数量的问题。如果我想控制那个,我可能需要覆盖frozenset.__new__
。另一方面,第一种方法通常可能更快,因为代理会产生一些开销。
我不知道这是否重要,但我通常会为Python 2.7编写。
答案 0 :(得分:1)
您需要问的问题是:my class is
或my class has
?,即典型的问题继承与组合。换句话说,您的Edge
是frozenset
还是恰好有一个供内部使用?
将其视为您班级的第三方用户。你得到一个Edge
对象。你看看它的API。你想在那里看到什么?可能允许您与Edge
逻辑域进行交互的方法,例如,嗯...... .do_what_edges_do()
,而不是.union()
或.isdisjoint()
,
在这种情况下,我很清楚你应该去作曲。如有疑问,请选择合成。
但是,您可能希望直接在API中公开冻结集的某些方法。 Python有很好的机制,但你必须将普通的y和魔术方法分开。
普通方法:
只需声明要公开的方法列表,然后使用__getattr__
。例如,我们假设您想要公开方法' abc'和' cde' (它们不存在于frozenset
中,这仅用于学习目的)
class Edge(object):
..
_exposed_methods = ['abc', 'cde']
def __getattr__(self, item):
if item in self._exposed_methods:
return getattr(self, item)
raise AttributeError
魔术方法:
以前的机制不适用于魔术方法,Python会跳过它来提高性能。在这种情况下,你必须明确地声明它们。例如,一个有用的__len__
class Edge(object):
..
def __len__(self):
return len(self._my_set)
阅读评论后编辑
你必须做出语义决定。我不知道Edge应该包含哪些对象,所以让我们说Item
objs。现在的问题是,您希望在代码的API中提供什么样的方法?
类似get_items
的内容?这强调了Item
的概念。在这种情况下,返回一个集合,如填充Item
s的集合是完全正确的。既然您说要为此集合添加更多方法,那么这可能不是您想要做的。
或get_edge
?这更加重视Edge
的概念。在这种情况下,您应该返回自己的Edge
类的实例。如果所有 frozenset
公开的方法对您的Edge
概念有意义,请继续使用。否则,去构图并只暴露有意义的东西(使用上述机制)。