【问题标题】:Proxying or subclassing base classes?代理或子类化基类?
【发布时间】:2014-11-12 23:21:42
【问题描述】:

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

【问题讨论】:

    标签: python subclass proxy-classes


    【解决方案1】:

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

    将其视为您班级的第三方用户。你得到一个Edge 对象。你看看它的API。你想在那里看什么?可能是允许您与Edge 逻辑域交互的方法,例如,嗯....do_what_edges_do(),而不是.union().isdisjoint() 之类的东西,

    在这种情况下,我很清楚你应该去作曲。如有疑问,请进行作文。

    但是,您可能希望直接在 API 中公开 freezeset 的某些方法。 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 的概念。在这种情况下,返回一个集合(如填充了Items 的集合)是完全正确的。既然你说你想给这个集合添加更多的方法,这可能不是你想要做的。

    • 还是get_edge?这更加重视Edge 的概念。在这种情况下,您应该返回您自己的 Edge 类的实例。如果frozenset 公开的所有方法对您的Edge 概念有意义,请选择继承。否则,请进行组合并仅公开有意义的内容(使用上述机制)。

    【讨论】:

    • 谢谢。然而,对我来说,这并不是那么清楚。我相信有一些更抽象思维的人会希望能够检查像if edge1() & edge2() 这样的东西(比如edge1edge2 intersect - as sets)。
    • 无论如何,对我来说,Edge 一个不可变的集合。子类化frozenset 仍然有很多问题,所以我不相信这是正确的做法。
    • 好吧,如果它只是一个集合,那么......使用一个集合。如果不需要特殊含义或功能,为什么还要费心创建自己的类?
    • 我没有说它只是一组。它是一个集合,但正如我在问题中所说,它应该公开许多额外的方法。
    猜你喜欢
    • 1970-01-01
    • 2018-01-30
    • 2016-01-17
    • 1970-01-01
    • 1970-01-01
    • 2012-03-22
    • 1970-01-01
    • 2018-12-30
    • 2013-01-11
    相关资源
    最近更新 更多