Python 代理或子类化基类?
这也许是一个过于笼统的问题,但它仍然困扰着我。一般来说,什么是更好的实践(为什么):代理或子类化基类?我所说的base是指一个标准类,它通常甚至没有用Python实现 一个更具体的问题如下:我希望为图边创建一个对象;图边本质上是一对两个顶点。顶点可以是任何可散列对象。我希望edge能够公开比Python 代理或子类化基类?,python,subclass,proxy-classes,Python,Subclass,Proxy Classes,这也许是一个过于笼统的问题,但它仍然困扰着我。一般来说,什么是更好的实践(为什么):代理或子类化基类?我所说的base是指一个标准类,它通常甚至没有用Python实现 一个更具体的问题如下:我希望为图边创建一个对象;图边本质上是一对两个顶点。顶点可以是任何可散列对象。我希望edge能够公开比frozenset公开更多的方法。所以我想知道我是否应该 class Edge(frozenset): def my_method(self, *args): return 3 或
frozenset
公开更多的方法。所以我想知道我是否应该
class Edge(frozenset):
def my_method(self, *args):
return 3
或
第一种方法的好处是我必须写得更少(因为我不必复制所有原始方法)。然而,第二种方法在某种意义上看起来更安全。它也更灵活,因为它允许我避免一些frozenset
公开的方法(如difference
),如果我愿意的话
第一个方法还引入了传递的参数数量问题。如果我想控制它,我可能必须覆盖冻结集。另一方面,第一种方法通常可能更快,因为代理会产生一些开销
我不知道这是否重要,但我通常为Python 2.7编写。您必须问的问题是:我的类是
还是我的类有
?,即继承与组合的典型问题。换句话说,您的Edge
是frozenset
还是恰好有一个供内部使用
将其视为类的第三方用户。您将获得一个边
对象。您可以看看它的API。你想在那里看什么?可能是允许您与边缘
逻辑域交互的方法,例如,uhmm.do\u what\u edges\u do()
,而不是像.union()
或.isdisjoint()
这样的事情
在这种情况下,我很清楚你应该选择作文。当有疑问时,就开始写作
但是,您可能希望直接在API中公开frozenset的一些方法。Python有很好的机制来实现这一点,但您必须区分普通的y方法和magic方法
常规方法:
只需声明一个要公开的方法列表,然后使用\uu getattr\uu
。例如,假设您想公开方法“abc”和“cde”(它们在冻结集中不存在,这只是为了学习)
魔法方法:
前面的机制不适用于神奇的方法,Python为了提高性能而跳过它。在这种情况下,您必须明确声明它们。例如,一个有用的
class Edge(object):
..
def __len__(self):
return len(self._my_set)
阅读评论后编辑
你必须做出语义上的决定。我不知道边应该包含哪些对象,所以让我们假设Item
objs。现在的问题是,您希望在代码的API中提供什么样的方法
- 类似于
get_items
?这强调了项
的概念。在这种情况下,返回一个集合(如用Item
s填充的集合)是完全正确的。因为您说要向该集合添加更多方法,所以这可能不是您想要做的
- 或
获取边缘
?这使得Edge
的概念更加重要。在这种情况下,您应该返回自己的Edge
类的实例。如果所有由frozenset
公开的方法对您的Edge
概念有意义,那么就选择继承。否则,进行合成并仅公开有意义的内容(使用上述机制)
谢谢。然而,对我来说,这并不清楚。我相信,有一些更抽象思维的人会希望能够检查像if edge1()&edge2()
(也就是说,edge1
和edge2
相交-作为集)。无论如何,对我来说,边是一个不变的集。但是,子类化frozenset
仍然有很多麻烦,所以我不相信这是正确的做法。如果它只是一个集合,那么。。。使用一套。如果不需要特殊的含义或功能,为什么还要创建自己的类呢?我没说它只是一个集合。这是一个集合,但正如我在问题中所说的,它应该公开许多额外的方法。
class Edge(object):
..
_exposed_methods = ['abc', 'cde']
def __getattr__(self, item):
if item in self._exposed_methods:
return getattr(self, item)
raise AttributeError
class Edge(object):
..
def __len__(self):
return len(self._my_set)