Attack a sacred Python Cow

Jordan jordanrastrick at gmail.com
Thu Jul 24 01:46:38 EDT 2008


On Jul 24, 3:41 pm, Jordan <jordanrastr... at gmail.com> wrote:
> Hi everyone,
>
> I'm a big Python fan who used to be involved semi regularly in
> comp.lang.python (lots of lurking, occasional posting) but kind of
> trailed off a bit. I just wrote a frustration inspired rant on my
> blog, and I thought it was relevant enough as a wider issue to the
> Python community to post here for your discussion and consideration.
>
> This is not flamebait. I love Python, and I'm not out to antagonise
> the community. I also realise that one of the issues I raise is way
> too ingrained to be changed now. I'd just like to share my thinking on
> a misstep in Python's guiding principles that has done more harm than
> good IMO. So anyway, here's the post.
>
> I've become utterly convinced that at least one criticism leveled at
> my favourite overall programming language, Python, is utterly true and
> fair. After quite a while away from writing Python code, I started
> last night on a whim to knock up some code for a prototype of an idea
> I once had. It's going swimmingly; the Python Image Library, which I'd
> never used before, seems quick, intuitive, and with the all the
> features I need for this project. As for Python itself, well, my heart
> still belongs to whitespace delimitation. All the basics of Python
> coding are there in my mind like I never stopped using them, or like
> I've been programming in this language for 10 years.
>
> Except when it comes to Classes. I added some classes to code that had
> previously just been functions, and you know what I did - or rather,
> forgot to do? Put in the 'self'. In front of some of the variable
> accesses, but more noticably, at the start of *every single method
> argument list.* This cannot be any longer blamed as a hangover from
> Java - I've written a ton more code, more recently in Python than in
> Java or any other OO language. What's more, every time I go back to
> Python after a break of more than about a week or so, I start making
> this 'mistake' again. The perennial justification for this 'feature'
> of the language? That old Python favourite, "Explicit is better than
> implicit."
>
> I'm sorry, but EXPLICIT IS NOT NECESSARILY BETTER THAN IMPLICIT.
> Assembler is explicit FFS. Intuitive, clever, dependable, expected,
> well-designed *implicit* behaviour is one of the chief reasons why I
> use a high level language. Implicitly garbage collect old objects for
> me? Yes, please!
>
> I was once bitten by a Python wart I felt was bad enough to raise and
> spend some effort advocating change for on comp.lang.python (never got
> around to doing a PEP; partly laziness, partly young and inexperienced
> enough to be intimidated at the thought. Still am, perhaps.)
>
> The following doesn't work as any sane, reasonable person would
> expect:
>
> # Blog code, not tested
> class A():
>   def __eq__(self, obj):
>     return True
> a = A()
> b = []
> assert a == b
> assert not (a != b)
>
> The second assertion fails. Why? Because coding __eq__, the most
> obvious way to make a class have equality based comparisons, buys you
> nothing from the != operator. != isn't (by default) a synonym for the
> negation of == (unlike in, say, every other language ever); not only
> will Python let you make them mean different things, without
> documenting this fact - it actively encourages you to do so.
>
> There were a disturbingly high number of people defending this
> (including one quite renowned Pythonista, think it might have been
> Effbot). Some had the temerity to fall back on "Explicit is better
> than implict: if you want != to work, you should damn well code
> __ne__!"
>
> Why, for heaven's sake, should I have to, when in 99.99% of use cases
> (and of those 0.01% instances quoted in the argument at the time only
> one struck me as remotely compelling) every programmer is going to
> want __ne__ to be the logical negation of __eq__? Why, dear Python,
> are you making me write evil Java-style language power reducing
> boilerplate to do the thing you should be doing yourself anyway?
> What's more, every programmer is going to unconciously expect it to
> work this way, and be as utterly as mystified as me when it fails to
> do so. Don't tell me to RTFM and don't tell me to be explicit. I'll
> repeat myself - if I wanted to be explicit, I'd be using C and
> managing my own memory thank you very much. Better yet, I'd explicitly
> and graphically swear - swear in frustration at this entrenched design
> philosophy madness that afflicts my favourite language.
>
> I think the real problem with the explicit is better than implicit,
> though, is that while you can see the underlying truth its trying to
> get at (which is perhaps better expressed by Ruby's more equivocal,
> less dependable, but more useful Principle of Least Surprise), in its
> stated form its actually kind of meanginless and is used mainly in
> defence of warts - no, we'll call them for what they are, a language
> design *bugs*.
>
> You see, the problem is, there's no such thing of explict in
> programming. Its not a question of not doing things implicitly; its a
> question of doing the most sensible thing implicitly. For example this
> python code:
>
> some_obj.some_meth(some_arg1, some_arg2)
>
> is implicitly equivalent to
>
> SomeClass.some_meth(some_obj, some_arg1, some_arg2)
>
> which in turn gives us self as a reference to some_obj, and Python's
> OO model merrily pretends its the same as Java's when in fact is a
> smarter version that just superficially looks the same.
>
> The problem is that the explicit requirement to have self at the start
> of every method is something that should be shipped off to the
> implicit category. You should have to be explicit, yes - explicit when
> you want the *other* behaviour, of self *not* being an argument,
> because thats the more unusual, less likely case.
>
> Likewise,
>
> a != b
>
> is implicitly equivalent to something like calling this function (may
> not be correct, its a while since I was heavily involved in this
> issue):
>
> def equal(a, b):
>   if hasattr(a, "__ne__"): return a.__ne__(b)
>   if hasattr(b, "__ne__"): return b.__ne__(a)
>   if hasattr(a, "__cmp__"): return not (a.__cmp__(b) == 0)
>   if hasattr(b, "__cmp__"): return not (b.__cmp__(a) == 0)
>   return not (a is b)
>
> There's absolutely nothing explicit about this. I wasn't arguing for
> making behaviour implicit; I was arguing for changing the stupid
> implict behaviour to something more sensible and less surprising.
>
> The sad thing is there are plenty of smart Python programmers who will
> justify all kinds of idiocy in the name of their holy crusade against
> the implict.
>
> If there was one change I could make to Python, it would be to get
> that damn line out of the Zen.

P.S. Forgive the typos, it was blogged in extreme haste and then only
quickly proofread and edited before posting here. Hopefully the point
I'm making is not diminshed by your reduced respect for me as a result
of my carelessness :-)



More information about the Python-list mailing list