Attack a sacred Python Cow

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Jordan

    Attack a sacred Python Cow

    Hi everyone,

    I'm a big Python fan who used to be involved semi regularly in
    comp.lang.pytho n (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.pytho n (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_m eth(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.
  • Jordan

    #2
    Re: Attack a sacred Python Cow

    On Jul 24, 3:41 pm, Jordan <jordanrastr... @gmail.comwrote :
    Hi everyone,
    >
    I'm a big Python fan who used to be involved semi regularly in
    comp.lang.pytho n (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.pytho n (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_m eth(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 :-)

    Comment

    • pluskid

      #3
      Re: Attack a sacred Python Cow

      On Jul 24, 1:41 pm, Jordan <jordanrastr... @gmail.comwrote :
      Hi everyone,
      >
      I'm a big Python fan who used to be involved semi regularly in
      comp.lang.pytho n (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.
      >
      [...snip...]

      +1 for most of your opinion. I was also bitten by the __eq__/__ne__
      problem this morning. :)

      Comment

      • Fredrik Lundh

        #4
        Re: Attack a sacred Python Cow

        Jordan wrote:
        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."
        Do you seriously think that Python is designed by mindless application
        of a set of humorous and somewhat self-deprecating observations posted
        to a newsgroup a number of years ago?

        </F>

        Comment

        • Jordan

          #5
          Re: Attack a sacred Python Cow

          Of course not.

          I just think Explicit is better than Implicit is taken seriously by a
          large segment the Python community as a guiding principle, and overall
          its influence does more harm than good.

          Clearly self being in every argument list was a decision arrived at
          long before the Zen was ever coined. Its merely an example of what I
          feel is a shortcoming in the conventional 'pythonic' approach to
          thinking about problems.

          The reluctance to admit that the __eq__ behaviour is a poor design
          choice is further evidence; its something (unlike self) that quite
          conceivably could be changed, and should be changed, but its somehow
          seen (by certain people) as the way that Python should do things.

          Comment

          • Torsten Bronger

            #6
            Re: Attack a sacred Python Cow

            Hallöchen!

            Bruno Desthuilliers writes:
            [...]
            >
            How would you handle this case with an implicit 'self' :
            >
            class Foo(object):
            pass
            >
            def bar(self):
            print self
            >
            Foo.bar = bar
            Just like this. However, the compiler could add "self" to
            non-decorated methods which are defined within "class".

            Tschö,
            Torsten.

            --
            Torsten Bronger, aquisgrana, europa vetus
            Jabber ID: torsten.bronger @jabber.rwth-aachen.de

            Comment

            • Jordan

              #7
              Re: Attack a sacred Python Cow

              On Jul 24, 7:40 pm, Torsten Bronger <bron...@physik .rwth-aachen.de>
              wrote:
              Hallöchen!
              >
              Bruno Desthuilliers writes:
              [...]
              >
              How would you handle this case with an implicit 'self' :
              >
              class Foo(object):
                 pass
              >
              def bar(self):
                 print self
              >
              Foo.bar = bar
              >
              Just like this.  However, the compiler could add "self" to
              non-decorated methods which are defined within "class".
              >
              Tschö,
              Torsten.
              >
              --
              Torsten Bronger, aquisgrana, europa vetus
                                 Jabber ID: torsten.bron... @jabber.rwth-aachen.de
              Yeah, forgot what I said, Torsten's reply is much better :-)

              Comment

              • Lawrence D'Oliveiro

                #8
                Re: Attack a sacred Python Cow

                In message
                <52404933-ce08-4dc1-a558-935bbbae779b@r3 5g2000prm.googl egroups.com>, Jordan
                wrote:
                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.*
                The reason is quite simple. Python is not truly an "object-oriented"
                language. It's sufficiently close to fool those accustomed to OO ways of
                doing things, but it doesn't force you to do things that way. You still
                have the choice. An implicit "self" would take away that choice.

                Comment

                • Sebastian \lunar\ Wiesner

                  #9
                  Re: Attack a sacred Python Cow

                  Jordan <jordanrastrick @gmail.com>:
                  # 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);
                  This is just plain wrong for at least C# and C++. C# wants you to
                  explicitly overload "!=", if you have overloaded "==", C++ complains
                  about "!=" not being defined for class A. If you had derived A from a
                  another class in C++, the compiler would happily use the operator from the
                  base class instead of doing silly aliasing of "!=" to "! ==" ...
                  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.
                  Fortunately, Python isn't designed according to your ideas, and won't
                  change, so consider your posting a waste of time. If feeling like bringing
                  such old "issues" up again next time, spend your time learning another
                  programming language, as you would obviously not get happy with Python
                  anyway ...

                  --
                  Freedom is always the freedom of dissenters.
                  (Rosa Luxemburg)

                  Comment

                  • Jordan

                    #10
                    Re: Attack a sacred Python Cow

                    This is just plain wrong for at least C# and C++.  C# wants you to
                    explicitly overload "!=", if you have overloaded "==",
                    While this is as inconvenient as Python at least it doesn't catch you
                    unawares. C# 1 (or maybe 0.5), Python 0.
                    C++ complains
                    about "!=" not being defined for class A.  
                    See above. C++ 1, Python 0.

                    So in showing my clearly hyperbolic comment was technically incorrect
                    (something I could have told you myself), you have merely shown that
                    two languages I find vastly inferior to Python overall are actually
                    better than it in this case.
                    Fortunately, Python isn't designed according to your ideas, and won't
                    change, so consider your posting a waste of time.  If feeling like bringing
                    such old "issues" up again next time, spend your time learning another
                    programming language, as you would obviously not get happy with Python
                    anyway ...
                    OK, if that's your response, that's sad. Of course, I try to learn new
                    languages all the time. Python is still IMO the best. If the attitude
                    in the community in response to feedback/criticism has gone from
                    "maybe you've got a point" to "your a lunatic, we'll never change",
                    well, only Python will suffer in the long term.

                    Comment

                    • Jordan

                      #11
                      Re: Attack a sacred Python Cow

                      On Jul 24, 8:01 pm, Lawrence D'Oliveiro <l...@geek-
                      central.gen.new _zealandwrote:
                      In message
                      <52404933-ce08-4dc1-a558-935bbbae7...@r3 5g2000prm.googl egroups.com>, Jordan
                      wrote:
                      >
                      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.*
                      >
                      The reason is quite simple. Python is not truly an "object-oriented"
                      language. It's sufficiently close to fool those accustomed to OO ways of
                      doing things, but it doesn't force you to do things that way. You still
                      have the choice. An implicit "self" would take away that choice.
                      You could still explicitly request non-implicit self on a method by
                      method basis.

                      Comment

                      • Kay Schluehr

                        #12
                        Re: Attack a sacred Python Cow

                        On 24 Jul., 11:40, Torsten Bronger <bron...@physik .rwth-aachen.de>
                        wrote:
                        Hallöchen!
                        >
                        Bruno Desthuilliers writes:
                        [...]
                        >
                        How would you handle this case with an implicit 'self' :
                        >
                        class Foo(object):
                        pass
                        >
                        def bar(self):
                        print self
                        >
                        Foo.bar = bar
                        >
                        Just like this. However, the compiler could add "self" to
                        non-decorated methods which are defined within "class".
                        And $self2, $self3, ... to the object methods of nested classes and
                        $cls2, $cls3, ... to the classmethods of those classes...?

                        And when we are at it, here is a nice little exercise for the
                        proponents of compiler magic.

                        Write a decorator that takes and returns a method and prints the
                        object the method is bound to. It's very easy to do it when the object
                        is passed explicitely:

                        def print_self(func ):
                        def call(self, *args, **kwd):
                        print self
                        return func(self, *args, **kwd)
                        return call

                        Conceptual clarity isn't always an entirely bad thing to have.

                        Comment

                        • Torsten Bronger

                          #13
                          Re: Attack a sacred Python Cow

                          Hallöchen!

                          Kay Schluehr writes:
                          On 24 Jul., 11:40, Torsten Bronger <bron...@physik .rwth-aachen.de>
                          wrote:
                          >>
                          >Bruno Desthuilliers writes:
                          >>
                          >>[...]
                          >>>
                          >>How would you handle this case with an implicit 'self' :
                          >>>
                          >>class Foo(object):
                          >> pass
                          >>>
                          >>def bar(self):
                          >> print self
                          >>>
                          >>Foo.bar = bar
                          >>
                          >Just like this. However, the compiler could add "self" to
                          >non-decorated methods which are defined within "class".
                          >
                          And $self2, $self3, ... to the object methods of nested classes
                          and $cls2, $cls3, ... to the classmethods of those classes...?
                          One could surely find ways to realise this. However, the design
                          goal should be: Make the frequent case simple, and the rare case
                          possible.

                          (Actually, I'm -0 on this anyway because I forget "self" very
                          seldomly, and you would still have ".self" all over the place.)

                          Tschö,
                          Torsten.

                          --
                          Torsten Bronger, aquisgrana, europa vetus
                          Jabber ID: torsten.bronger @jabber.rwth-aachen.de

                          Comment

                          • alex23

                            #14
                            Re: Attack a sacred Python Cow

                            On Jul 24, 8:21 pm, Jordan <jordanrastr... @gmail.comwrote :
                            If the attitude
                            in the community in response to feedback/criticism has gone from
                            "maybe you've got a point" to "your a lunatic, we'll never change",
                            well, only Python will suffer in the long term.
                            Personally, I think it has more to do with statements like "there are
                            plenty of smart Python programmers who will
                            justify all kinds of idiocy in the name of their holy crusade" than
                            with your position. You don't begin a discussion by discrediting
                            anyone who might disagree with you as some kind of religious bigot
                            while simultaneously holding that you are the only sane voice
                            speaking.

                            Comment

                            • Sebastian \lunar\ Wiesner

                              #15
                              Re: Attack a sacred Python Cow

                              Jordan <jordanrastrick @gmail.com>:
                              >Fortunately, Python isn't designed according to your ideas, and won't
                              >change, so consider your posting a waste of time.  If feeling like
                              >bringing such old "issues" up again next time, spend your time learning
                              >another programming language, as you would obviously not get happy with
                              >Python anyway ...
                              >
                              OK, if that's your response, that's sad. Of course, I try to learn new
                              languages all the time. Python is still IMO the best. If the attitude
                              in the community in response to feedback/criticism has gone from
                              "maybe you've got a point" to "your a lunatic, we'll never change",
                              well, only Python will suffer in the long term.
                              I don't really mind, what you think about my response. Python will suffer
                              from it as little as it will suffer from your complaints: These things
                              will not change, whatever any of us says about them. So this discussion
                              unlikely to produce any new insight, especially because this as been
                              discussed over and over again in the past, without any effect on Python.

                              Let's just drop this, and if you want to complain next time, just complain
                              about something, that is really worth being complained about, like for
                              instance old and outdated modules in the standard library, or real
                              showstoppers in Python (e.g. the GIL).

                              --
                              Freedom is always the freedom of dissenters.
                              (Rosa Luxemburg)

                              Comment

                              Working...