代理或继承基类?

时间:2014-11-12 11:16:07

标签: python subclass proxy-classes

这可能是一个太普遍的问题,但仍困扰着我。一般来说,什么是更好的实践(以及为什么):代理或子类化基类? 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编写。

1 个答案:

答案 0 :(得分:1)

您需要问的问题是:my class ismy class has ?,即典型的问题继承与组合。换句话说,您的Edgefrozenset还是恰好有一个供内部使用?

将其视为您班级的第三方用户。你得到一个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概念有意义,请继续使用。否则,去构图并只暴露有意义的东西(使用上述机制)。