[Python-Dev] PEP 8 updates/clarifications
Ian Bicking
ianb at colorstudy.com
Sun Dec 11 23:30:51 CET 2005
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 | ianb at colorstudy.com | http://blog.ianbicking.org
More information about the Python-Dev
mailing list