Python 中的访问器是否合理?
我意识到在大多数情况下,Python 中最好直接访问属性,因为没有像 Java 等中那样的真正的封装概念。但是,我想知道是否没有任何例外,特别是对于具有不同实现的抽象类。
假设我正在编写一堆抽象类(因为我就是这样),并且它们代表与版本控制系统(如存储库和修订版)有关的事物(因为它们确实如此)。像 SvnRevision 和 HgRevision 以及 GitRevision 这样的东西在语义上联系非常紧密,我希望它们能够做同样的事情(这样我就可以在其他地方拥有作用于任何类型的 Repository 对象的代码,并且不知道子类),这就是为什么我希望它们继承抽象类。然而,它们的实现差异很大。
到目前为止,已经实现的子类共享很多属性名称,并且在类本身之外的很多代码中,使用了直接属性访问。例如,Revision 的每个子类都有一个作者属性和一个日期属性等。但是,抽象类中的任何地方都没有描述这些属性。在我看来,这是一个非常脆弱的设计。
如果有人想编写 Revision 类的另一个实现,我觉得他们应该只需查看抽象类就可以做到这一点。然而,满足所有抽象方法的类的实现几乎肯定会失败,因为作者不知道他们需要名为“author”和“date”等属性,因此尝试访问 Revision 的代码。作者将抛出异常。找到问题的根源可能并不难,但仍然令人恼火,而且感觉设计不优雅。
我的解决方案是为抽象类(get_id、get_author 等)编写访问器方法。我认为这实际上是一个非常干净的解决方案,因为它消除了对属性命名和存储方式的任意限制,并且只是明确了对象需要能够访问哪些数据。任何实现抽象类的所有方法的类都可以工作......这感觉是对的。
无论如何,与我一起工作的团队讨厌这个解决方案(似乎是因为访问器不符合Pythonic,我无法真正争论)。那么...还有什么选择呢?文档?或者我想象的问题不是问题?
注意:我已经考虑过属性,但我认为它们不是一个更干净的解决方案。
I realize that in most cases, it's preferred in Python to just access attributes directly, since there's no real concept of encapsulation like there is in Java and the like. However, I'm wondering if there aren't any exceptions, particularly with abstract classes that have disparate implementations.
Let's say I'm writing a bunch of abstract classes (because I am) and that they represent things having to do with version control systems like repositories and revisions (because they do). Something like an SvnRevision and an HgRevision and a GitRevision are very closely semantically linked, and I want them to be able to do the same things (so that I can have code elsewhere that acts on any kind of Repository object, and is agnostic of the subclass), which is why I want them to inherit from an abstract class. However, their implementations vary considerably.
So far, the subclasses that have been implemented share a lot of attribute names, and in a lot of code outside of the classes themselves, direct attribute access is used. For example, every subclass of Revision has an author attribute, and a date attribute, and so on. However, the attributes aren't described anywhere in the abstract class. This seems to me like a very fragile design.
If someone wants to write another implementation of the Revision class, I feel like they should be able to do so just by looking at the abstract class. However, an implementation of the class that satisfies all of the abstract methods will almost certainly fail, because the author won't know that they need attributes called 'author' and 'date' and so on, so code that tries to access Revision.author will throw an exception. Probably not hard to find the source of the problem, but irritating nonetheless, and it just feels like an inelegant design.
My solution was to write accessor methods for the abstract classes (get_id, get_author, etc.). I thought this was actually a pretty clean solution, since it eliminates arbitrary restrictions on how attributes are named and stored, and just makes clear what data the object needs to be able to access. Any class that implements all of the methods of the abstract class will work... that feels right.
Anyways, the team I'm working with hates this solution (seemingly for the reason that accessors are unpythonic, which I can't really argue with). So... what's the alternative? Documentation? Or is the problem I'm imagining a non-issue?
Note: I've considered properties, but I don't think they're a cleaner solution.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
但它们确实如此。 通过使用属性,您将获得所需的类签名,同时能够将该属性用作属性本身。
可能与您现在拥有的类似。为了安抚您的团队,您只需要添加以下内容:
您还可以使用
property
作为装饰器:要使其只读,只需省略
set_id
/theid.setter
位。But they are. By using properties, you'll have the class signature you want, while being able to use the property as an attribute itself.
Is likely similar to what you have now. To placate your team, you'd just need to add the following:
You could also use
property
as a decorator:And to make it readonly, just leave out
set_id
/theid.setter
bit.你错过了重点。并不是由于缺乏封装而不再需要访问器,而是事实是,通过从直接属性更改为属性,您可以在以后添加访问器,而无需以任何方式更改已发布的接口。
在许多其他语言中,如果您将一个属性公开为公共属性,然后想要在访问或更改时包装一些代码,那么您必须更改接口,并且使用该代码的任何人至少必须重新编译并可能编辑其属性码也。 Python 不是这样的:您可以根据需要在属性或属性之间进行切换,并且使用该类的代码不会被破坏。
You've missed the point. It isn't the lack of encapsulation that removes the need for accessors, it's the fact that, by changing from a direct attribute to a property, you can add an accessor at a later time without changing the published interface in any way.
In many other languages, if you expose an attribute as public and then later want to wrap some code round it on access or mutation then you have to change the interface and anyone using the code has at the very least to recompile and possibly to edit their code also. Python isn't like that: you can flip flop between attribute or property just as much as you want and no code that uses the class will break.
仅在属性后面。
Only behind a property.
不知道这应该是什么。 “程序员指南”、“如何扩展”文档以及一些培训对我来说似乎很合适。
在这种情况下,文档并不完整。也许抽象类需要更好的文档字符串。或者“程序员指南”,或者“如何扩展”文档。
此外,(1) 在文档字符串中记录这些属性并 (2) 在 __init__ 方法中提供默认值似乎并不困难。
为程序员提供额外的支持有什么问题吗?
听起来你遇到的是社会问题,而不是技术问题。编写代码来解决社会问题似乎是浪费时间和金钱。
Don't know what this should be true. A "programmer's guide", a "how to extend" document, plus some training seems appropriate to me.
In that case, the documentation isn't complete. Perhaps the abstract class needs a better docstring. Or a "programmer's guide", or a "how to extend" document.
Also, it doesn't seem very difficult to (1) document these attributes in the docstring and (2) provide default values in the
__init__
method.What's wrong with providing extra support for programmers?
It sounds like you have a social problem, not a technical one. Writing code to solve a social problem seems like a waste of time and money.
讨论一年前就已经结束了,但这个片段似乎很能说明问题,值得讨论:
呃,有什么事情是严重错误的。 (S. Lott 所说的,减去个人评论)。
如果这些是必需的成员,那么它们不是在构造函数中引用(如果不需要)并由文档字符串定义吗?或者至少,按照方法所需的参数,并再次记录?
类的用户怎么不知道所需的成员是什么?
作为魔鬼的拥护者,如果您的构造函数要求您提供将要/可能需要的所有成员怎么办,这会导致什么问题?
另外,您是否在传递时检查参数并抛出信息异常?
(访问器与属性的意识形态争论是一个侧边栏。属性更可取,但我认为这不是您的类设计的问题。)
The discussion already ended a year ago, but this snippet seemed telltale, it's worth discussing:
Uh, something is deeply wrong. (What S. Lott said, minus the personal comments).
If these are required members, aren't they referenced (if not required) in the constructor, and defined by docstring? or at very least, as required args of methods, and again documented?
How could users of the class not know what the required members are?
To be the devil's advocate, what if your constructor(s) requires you to supply all the members that will/may be required, what issue does that cause?
Also, are you checking the parameters when passed, and throwing informative exceptions?
(The ideological argument of accessor-vs-property is a sidebar. Properties are preferable but I don't think that's the issue with your class design.)