[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