Jim Fulton wrote: >> Designing for inheritance >> >> Always decide whether a class's methods and instance variables >> should be public or non-public. In general, never make data >> variables public unless you're implementing essentially a >> record. It's almost always preferrable to give a functional > > > interface to your class instead (and some Python 2.2 > > developments will make this much nicer). > > > > Yes, Python 2.2 developments have made this better. Use of property() > > should be suggested. > > This seems outdated. My impression, in part from time spent > working with the Python Labs guys, is that it is fine to have public > data sttributes even for non-"record" types. In fact, I would argue that > any time you would be tempted to provide "getFoo()" and "setFoo(v)" > for some "private attribute _foo", it would be better to make it > public. I certainly find "blah.foo" and "blah.foo = v" to be much > better than "blah.getFoo()" and blah.setFoo(v)". > > Certainly, properties provide a safety belt. I would argue it this > way: Python APIs can include attributes as well as methods. > Exposure of an attribute need not constrain the implementation, thanks > to properties. OTOH, I wouldn't bother with a property unless it's needed.
So, getting back to the original paragraph, perhaps it could say: Decide whether a class's methods and instance variables should be public or non-public. Non-public methods and variables should start with an underscore. Do not use accessor methods, like ``obj.getFoo()`` and ``obj.setFoo(v)``, instead just expose a public attribute (``obj.foo``). If necessary you can use ``property`` to implement the same functionality that accessor methods would give you. If you do use properties, getting that property should never have a side effect. [well... I think that certain side effects like caching and logging are okay, but I'm not sure how to make that distinction] Potentially it could be added that the whole issue can often be avoided when an object's methods perform actions instead of returning attributes of the object. It's a long topic; maybe it could even just be a link, if someone knows of a good discussion along those lines. I'm sure there's some terminology here that I'm forgetting that describes the design pattern. There's also a point when the style guide becomes an API design guide, and I don't know how far it should go in that direction. >> Also decide whether your attributes should be private or not. >> The difference between private and non-public is that the former >> will never be useful for a derived class, while the latter might >> be. Yes, you should design your classes with inheritence in >> mind! >> >> Private attributes should have two leading underscores, no >> trailing underscores. >> >> This conflicts with a previous suggestion "Generally, double leading >> underscores should be used only to avoid name conflicts with >> attributes in classes designed to be subclassed." Or perhaps "private >> attributes" needs to be better explained. > > > While, on some level, private variables seem attractive, I think that > experience (for everyone I know) has shown them to be an attractive > nuisance. I recommend discouraging them. I really really hate double underscores, but I thought I'd let some other people suggest stronger language first. I prefer explicit name mangling for those cases where people justifiably use double underscores now, e.g., self._MyPackage_variable instead of self.__variable, which I think you also suggest below. Since it's all name mangling anyway, at least explicit is better than implicit, especially when it's something one could argue *should* look a little ugly. Perhaps all the non-public/private language should be switched to just "private" (one underscore) and "hidden from subclasses" (double underscore). I don't like calling __ private at all, because it's not what people coming from other languages think of as private. > I'll note that, IMO: > > - If you have to worry about protecting attributes from subclasses, > maybe should shouldn't be using inheritence. > > (This may be too bold a statement, but perhaps the first > rule of inheritence should echo Fowler's first rule of Distribution: > "don't inherit". :) > > Increasingly, I like to use inheritence only to avoid "boiler plate" > implementations, such as default methods or data implementations that > almost all implementations of some API are going to do the same way. > > On rare occasions, I find inheritence to be, sadly, unavoidable. > > I should also make a distinction between what I would call "private" > and "public" inheritence. Private inheritence is between classes > that are part of a single implementation unit or having a single > implementor. With private inheritence, there is much less danger > since the same people are responsible for the base classes > and subclasses. It is public inheritence, where separate people > maintain the base and subclasses where I think inhetitence should > be used sparingly. > > Public inheritence causes too much coupling. > ) I think this is getting more into design, and less style guide. > - If you really have to use "public" inheritence, then consider naming > conventions. I think ZODB's use of the _p_ variables has worked well > for variables reserved for the base class attributes. (Although, I > think if I could do it over, I would use _persistent_ rather than > _p_.) > > I'll also note that, when providing "transpatent" facilities, like > persistence or proxies whos functions are orthogonal to subclass > or proxied-object functionality, I've come to prefer the use of external > functions to access provided functionality. For example, rather than > using something like: "someproxy._proxy_object" to get a proxied object > from a proxy, I use "getProxiedObject(someproxy)". This allows the > proxies themselves to remain as transparent as possible. I intend > to take a similar approach with future versions of ZODB's persistence > framework to avoid _p_ attributes and methods. This fits Python's style as well, i.e., len(obj) instead of obj.len(). Well, kind of. When to use functions instead of methods is a whole discussion of its own. >> Non-public attributes should have a single leading underscore, >> no trailing underscores. >> >> Public attributes should have no leading or trailing >> underscores, unless they conflict with reserved words, in which >> case, a single trailing underscore is preferrable to a leading >> one, or a corrupted spelling, e.g. class_ rather than klass. >> (This last point is a bit controversial; if you prefer klass >> over class_ then just be consistent. :). >> >> With class methods, this has become a more important. Can PEP 8 >> include a preferred name for the class argument to classmethods? I >> personally prefer cls, there are some who use klass, and I haven't see >> class_ used. > > > FWIW, as a general rule, I like using a single trailing underscore, > especially for keywords. It allows the use of meaningful and easy > to remember names. When the name of a variable should be "class" or > "for" or whatever, it's easy, as a Python programmer, to remember that > I need to add a trailing _. As a reformed abuser of single-character > variable names, I've come to really hate abbreviations. It's not only > easier to use unabbreviated names, it's easier to remember them when > reading code. (Note that ease of use hinges on editors that automate > typeing of repeated names.) What about for class methods in particular; do you use class_ as the first argument for those methods? Also, in the case of builtins, trailing _'s are dangerous; unlike keywords you won't get a SyntaxError if you leave the _ off, or even a NameError. As I think about it, I should really change my own style to stop using even corruptions like lst, but perhaps seq instead. But that's wandering off in a different direction from keywords. -- Ian Bicking | [EMAIL PROTECTED] | http://blog.ianbicking.org _______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com