Does Python really follow its philosophy of "Readability counts"?

Carl Banks pavlovevidence at gmail.com
Sun Jan 11 23:42:42 CET 2009


On Jan 11, 3:22 pm, "Madhusudan.C.S" <madhusuda... at gmail.com> wrote:
>   I am sorry all I am not here to just blame Python. This is just an
> introspection of whether
> what I believe is right. Being a devotee of Python from past 2 years I
> have been writing only
> small apps and singing praises about Python where ever I go. I now got
> a chance to read
> Django's code for some reason. I have now strongly started feeling if
> Python really follows its
> "Readability Counts" philosophy.

Ok, let's clear up a couple misconceptions right now.

First: "Reabability counts" is a design principle of the language, not
a mandate that every Python programmer write readable code.  If Django
project wants to write less readable code, they can.  "Readability
counts" means that Python is designed to make it easy for the Django
project to write readable code if they choose.

Second: "Readability counts" is not the only factor that matters.
There are 19 Zen and sometimes they conflict with each other.  Python
tries to balance all these concerns; it doesn't greedily maximize any
one of them.  Some things might be a little less readable than they
could be, but oftentimes that's because other design considerations
were judged more important in that case.

Having cleared that up, let's consider your specific points.

> For example,
>
>     class A:
>     a = 10
>     b = "Madhu"
>
>     def somemethod(self, arg1):
>         self.c = 20.22
>         d = "some local variable"
>         # do something
>         ....
>     ...
>     def somemethod2 (self, arg2):
>         self.c = "Changed the variable"
>         # do something 2
>         ...
>
> In such situations, where the Instance variables come into existence
> only when they are used
> it is very difficult to track the flow of code. Its obviously not
> possible to remember what
> instance variable was defined where, when reading some substantial
> amount of code

Impossible?  You are seriously overstating things.

> and where
> it was manipulated for that matter.

This criticism is completely unfair.  Instance variables have to be
manipulated somewhere, and unless your object is immutable, that is
going to happen outside of __init__.  That's true in Java, C++, and
pretty much any other language.

> It becomes so very frustrating
> even when reading a Class's
> code with just 6-8 methods and not more than 100-150 lines of code.
>
> I am interested in knowing if I am reading this kind of code in the
> wrong way mostly because
> of C++/Java hangover since most other languages follow the same
> approach as them?

(Well, it is a lot safer in Python.  In C++, if you try to use an
uninitialized variable, you'd get undefined behavior.  Better to
initialize it to null and at least get a guaranteed segfault.  In
Python if you try to use an uninitialized variable you'd get an
AttributeError.)

> If there
> is a Pythonic way reading this code for better readability? What made
> Python developers to
> adopt this strange strategy keeping "Readibility Counts" in mind?

I'm not going to argue that this doesn't hurt readability, because it
does (though not nearly as much as you claim).  But there are other
considerations, and in this case the flexibility of defining
attributes outside __init__ is worth the potential decrease in
readability.

Here's a couple examples of where it's useful:

1. Sometimes classes are initialized without calling __init__, strange
but true.  Look at the pickle module, for instance.  It creates the
object without calling __init__ then sets all the instance variables
itself.

2. Some classes have factory classmethods that create the object by a
different means than calling __init__.  (In fact, some classes have an
internal method that initializes variables, which __init__ and the
factories both call.)

3. Some objects, such as proxies, have uncertain sets of attributes.
Requiring such objects to predict all the variables they need inside
__init__ would limit their usability.  Programmers would probably
resort to hack-like workarounds like Decorator Design Pattern.

4. It allows a simplification of the object system.  Right now, all
attribute access is handled identically: at any point in time any
attribute may be set.  If you wanted to limit attribute creation to
__init__, then it would mean objects have to have two phases (one,
during __init__, where you can create attributes; the other, where you
can only modify them).  This would add significant complexity, and
"Simple is better than complex.

I'll also point out that even in C++/Java/etc. you have occasions
where an instance variable doesn't do anything until a something
triggers it.  You can look to the constructor to see what it's
initialized to, but it isn't really initialized to anything useful
until some method call sets it to something useful.  (Python makes it
explicit that the variable isn't in use until it is initialized, and
"Explicit is better than implicit".)


In the end, the answer to you question is simply, "Readibilty counts,
but other stuff matters too."


Carl Banks



More information about the Python-list mailing list