views:

95

answers:

4

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.

A: 

Only behind a property.

Ignacio Vazquez-Abrams
Thanks, but that doesn't really address my concern (not being able to implement the abstract class by just looking at the class definition itself). Also, just so it's clear, I'm not a Java (or C++, or whatever) programmer trying to justify shoehorning Java idioms into Python code. I've written very little Java, and I'm not a fan of the language at all.
Coquelicot
The fact that the other language in the video is Java is irrelevant. Using accessors directly requires changes to the client code, in *any* language.
Ignacio Vazquez-Abrams
+1  A: 

"they should be able to do so just by looking at the abstract class"

Don't know what this should be true. A "programmer's guide", a "how to extend" document, plus some training seems appropriate to me.

"the author won't know that they need attributes called 'author' and 'date' and so on".

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
Hey, I came here for programming advice. If I wanted to be psychoanalyzed, I'd go to FreudOverflow.Anyways, I do like the idea of putting documention in the constructor of the base class as an alternative.
Coquelicot
@ Coquelicot: I'm talking about cheap, pragmatic, low-risk software development. Writing *more* code to "solve" someone else's problem isn't high-value software. Educating other developers and writing less code reduces costs and risks.
S.Lott
+2  A: 

Note: I've considered properties, but I don't think they're a cleaner solution.

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.

def _get_id(self):
   return self._id

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

Is likely similar to what you have now. To placate your team, you'd just need to add the following:

id = property(_get_id, _set_id)

You could also use property as a decorator:

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

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

And to make it readonly, just leave out set_id/the id.setter bit.

JAB
+2  A: 

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.

Duncan