Python中的访问器是否合理?

时间:2010-07-20 17:26:50

标签: python inheritance interface attributes abstract-class

我意识到在大多数情况下,Python中首选只是直接访问属性,因为没有像Java等那样真正的封装概念。但是,我想知道是否没有任何异常,特别是对于具有不同实现的抽象类。

假设我正在编写一堆抽象类(因为我是),并且它们代表了与版本控制系统(如存储库和修订版)有关的事情(因为它们确实如此)。像SvnRevision和HgRevision以及GitRevision这样的东西在语义上非常紧密地联系在一起,我希望它们能够做同样的事情(这样我就可以将代码放在其他任何类型的Repository对象上,并且不可知子类),这就是为什么我希望它们从抽象类继承。但是,它们的实现差异很大。

到目前为止,已实现的子类共享许多属性名称,并且在类本身之外的许多代码中,使用直接属性访问。例如,Revision的每个子类都有author属性和date属性,依此类推。但是,抽象类中的任何位置都不会描述这些属性。在我看来,这似乎是一个非常脆弱的设计。

如果有人想编写Revision类的另一个实现,我觉得他们应该只通过查看抽象类就可以这样做。但是,满足所有抽象方法的类的实现几乎肯定会失败,因为作者不会知道他们需要名为“author”和“date”等的属性,因此尝试访问Revision的代码。作者将抛出异常。可能不难找到问题的根源,但仍然很烦人,而且感觉就像一个不雅的设计。

我的解决方案是为抽象类(get_id,get_author等)编写访问器方法。我认为这实际上是一个非常干净的解决方案,因为它消除了对属性命名和存储方式的任意限制,并且只是明确了对象需要能够访问的数据。任何实现抽象类的所有方法的类都可以工作......感觉正确。

无论如何,我正在工作的团队讨厌这个解决方案(似乎因为访问者是untythonic的原因,我无法真正争辩)。那么......有什么选择呢?文档?或者是我想象的问题是什么?

注意:我考虑了属性,但我认为它们不是一个更清洁的解决方案。

5 个答案:

答案 0 :(得分:8)

  

注意:我考虑了属性,但我认为它们不是一个更清洁的解决方案。

But they are.通过使用属性,您将拥有所需的类签名,同时能够将该属性用作属性本身。

def _get_id(self):
   return self._id

def _set_id(self, newid):
   self._id = newid

可能与你现在的相似。为了安抚您的团队,您只需要添加以下内容:

id = property(_get_id, _set_id)

你也可以使用property作为装饰者:

@property
def id(self):
    return self._id

@id.setter
def id(self, newid):
    self._id = newid

为了使其成为只读,请忽略set_id / id.setter位。

答案 1 :(得分:4)

你错过了这一点。缺少封装不会消除对访问器的需求,事实上,通过从直接属性更改为属性,您可以在以后添加访问器而无需以任何方式更改已发布的接口。

在许多其他语言中,如果将属性公开为public,然后又想要在访问或变异上包围一些代码,则必须更改接口,并且使用该代码的任何人至少都要重新编译并且可能也编辑他们的代码。 Python不是那样的:你可以根据需要在属性或属性之间进行翻转,并且没有使用该类的代码会破坏。

答案 2 :(得分:1)

答案 3 :(得分:1)

  

“他们应该只通过查看抽象类”

来做到这一点

不知道这应该是什么。 “程序员指南”,“如何扩展”文档以及一些培训对我来说似乎是合适的。

  

“作者不会知道他们需要名为'author'和'date'等属性”。

在这种情况下,文档不完整。也许抽象类需要更好的文档字符串。或者是“程序员指南”,或“如何扩展”文档。

此外,(1)在docstring中记录这些属性并且(2)在__init__方法中提供默认值似乎并不困难。

为程序员提供额外支持有什么问题?

听起来你有一个社会问题,而不是技术问题。编写解决社会问题的代码似乎浪费时间和金钱。

答案 4 :(得分:0)

讨论已于一年前结束,但这个片段似乎很明显,值得讨论:

  

但是,执行了   满足所有的类   几乎可以肯定抽象方法   失败,因为作者不会知道   他们需要所谓的属性   '作者'和'约会'等等,所以代码   尝试访问Revision.author   会抛出异常。

呃,有些事情是错误的。 (S. Lott说,减去个人评论)。 如果这些是必需的成员,它们是否在构造函数中引用(如果不是必需的话),并由docstring定义?或者至少,作为方法的必要方法,并再次记录? 班级的用户如何知道所需成员是什么? 要成为魔鬼的拥护者,如果您的构造函数要求您提供将要/可能需要的所有成员,这会导致什么问题呢? 你是否在传递时检查参数,并抛出信息性异常?

(accessor-vs-property的意识形态论证是一个侧边栏。属性更可取,但我不认为这是你班级设计的问题。)