[Python-Dev] PEP 8 updates/clarifications (original) (raw)
Ian Bicking ianb at colorstudy.com
Sun Dec 11 23:30:51 CET 2005
- Previous message: [Python-Dev] PEP 8 updates/clarifications
- Next message: [Python-Dev] Deprecate __ private (was Re: PEP 8 updates/clarifications)
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
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.proxyobject" 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 | ianb at colorstudy.com | http://blog.ianbicking.org
- Previous message: [Python-Dev] PEP 8 updates/clarifications
- Next message: [Python-Dev] Deprecate __ private (was Re: PEP 8 updates/clarifications)
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]