FAQ
I may be attempting something improper here, but maybe I'm just going
about it the wrong way. I'm subclassing
http.server.CGIHTTPRequestHandler, and I'm using a decorator to add
functionality to several overridden methods.

def do_decorate(func):
. def wrapper(self):
. if appropriate():
. return func()
. complain_about_error()
. return wrapper

class myHandler(CGIHTTPRequestHandler):
. @do_decorate
. def do_GET(self):
. return super().do_GET()
. # also override do_HEAD and do_POST

My first thought was that I could just replace that whole method
definition with one line:

class myHandler(CGIHTTPRequestHandler):
. do_GET = do_decorate(super().do_GET)

That generates the following error:

SystemError: super(): __class__ cell not found

So I guess that when super() is called in the context of a class def
rather than that of a method def, it doesn't have the information it
needs. Now I'll probably just say:

do_GET = do_decorate(CGIHTTPRequestHandler.do_GET)

but I wonder if there is a "correct" way to do this instead? Thanks!

Search Discussions

  • Ian Kelly at May 25, 2011 at 6:31 pm

    On Wed, May 25, 2011 at 11:54 AM, Jess Austin wrote:
    So I guess that when super() is called in the context of a class def
    rather than that of a method def, it doesn't have the information it
    needs. Now I'll probably just say:

    ? ?do_GET = do_decorate(CGIHTTPRequestHandler.do_GET)

    but I wonder if there is a "correct" way to do this instead? Thanks!
    I would recommend against using super() in general.

    http://fuhm.net/super-harmful/

    Cheers,
    Ian
  • Eric Snow at May 25, 2011 at 8:49 pm

    On Wed, May 25, 2011 at 12:31 PM, Ian Kelly wrote:
    On Wed, May 25, 2011 at 11:54 AM, Jess Austin wrote:
    So I guess that when super() is called in the context of a class def
    rather than that of a method def, it doesn't have the information it
    needs. Now I'll probably just say:

    do_GET = do_decorate(CGIHTTPRequestHandler.do_GET)

    but I wonder if there is a "correct" way to do this instead? Thanks!
    I would recommend against using super() in general.
    That position is understandable. However, super is fine for single
    inheritance, and works fine in cooperative multiple inheritance. You can
    just as easily argue that multiple inheritance is more harmful than super
    is. If fact, I would generally recommend against using multiple inheritance
    if you can avoid it (though it has its place).

    Personally, I find super to make maintenance and refactoring easier, since I
    don't have to fiddle with the base class name, or with passing self.

    Cheers,

    -eric
  • Steven D'Aprano at May 25, 2011 at 9:40 pm

    On Wed, 25 May 2011 12:31:33 -0600, Ian Kelly wrote:

    I would recommend against using super() in general.

    http://fuhm.net/super-harmful/
    If you actually read that article, carefully, without being fooled by the
    author's provocative ex-title and misleading rhetoric, you will discover
    that super is not harmful. What is harmful is making unjustified
    assumptions about what super does, and about the code you are calling,
    and hence misusing super.

    You have to read all the way to the bottom of the article to see the
    author say in the TODO section:

    "Give some examples of why super really is necessary sometimes"

    Even before that, you will read why *not* using super often fails badly.
    If James Knight, the author, is correct that super is harmful, it seems
    that you're in trouble because *not using super* is also harmful.

    If you search the mailing lists of python-dev at python.org, you will find a
    debate between James and Guido van Russum where James eventually
    acknowledges that he is wrong to call super harmful. There's a reason
    that he has changed the title of the page from "Python's Super Considered
    Harmful" to the damning-with-faint-praise "Python's Super is nifty, but
    you can't use it".

    The new title is also *simply wrong*, because you can use it. James even
    tells you what you need to do to use it correctly.

    The truth is that for multiple inheritance, you better be using super or
    your code is probably buggy (unless you manually duplicate what super
    does for you). And for single inheritance, it makes no difference whether
    you use super or not.



    --
    Steven
  • Ian Kelly at May 25, 2011 at 11:31 pm

    On Wed, May 25, 2011 at 3:40 PM, Steven D'Aprano wrote:
    If you actually read that article, carefully, without being fooled by the
    author's provocative ex-title and misleading rhetoric, you will discover
    that super is not harmful. What is harmful is making unjustified
    assumptions about what super does, and about the code you are calling,
    and hence misusing super.
    Yes. As others have noted, the problem is really multiple
    inheritance, not super. Super can be a useful tool, but unless you
    have taken some time to learn its intricacies, I think that it is best
    avoided so that it is not misused.
    You have to read all the way to the bottom of the article to see the
    author say in the TODO section:

    "Give some examples of why super really is necessary sometimes"

    Even before that, you will read why *not* using super often fails badly.
    If James Knight, the author, is correct that super is harmful, it seems
    that you're in trouble because *not using super* is also harmful.
    Essentially, super can fail when you use it inconsistently. Not using
    super can fail when you have a diamond inheritance situation, or when
    you mix it with super.

    In this case, the OP is using super while inheriting from
    http.server.CGIHTTPServer, which does not use super, and so is
    inconsistent.
    If you search the mailing lists of python-dev at python.org, you will find a
    debate between James and Guido van Russum where James eventually
    acknowledges that he is wrong to call super harmful. There's a reason
    that he has changed the title of the page from "Python's Super Considered
    Harmful" to the damning-with-faint-praise "Python's Super is nifty, but
    you can't use it".
    Thanks. I found this quote from James that pretty much sums up my
    position perfectly:

    """
    This is where I'm coming from:
    In my own code, it is very rare to have diamond inheritance structures.
    And if there are, even more rare that both sides need to cooperatively
    override a method. Given that, super has no necessary advantage. And it
    has disadvantages.
    - Backwards compatibility issues
    - Going along with that, inadvertent mixing of paradigms (you have to
    remember which classes you use super with and which you don't or your
    code might have hard-to-find errors).
    - Take your choice of: a) inability to add optional arguments to your
    methods, or b) having to use *args, **kwargs on every method and call
    super with those.
    - Having to try/catch AttributeErrors from super if you use interfaces
    instead of a base class to define the methods in use.
    """
    The new title is also *simply wrong*, because you can use it. James even
    tells you what you need to do to use it correctly.
    Yes, you need to fundamentally alter the structure of your code to
    throw away any semblance of run-time argument checking by having every
    method that might conceivably be cooperatively inherited take *args,
    **kwargs. You also need to take care to always call super from such
    methods, even when it appears to be unnecessary. And don't forget to
    catch the AttributeError if the method is something other than __new__
    or __init__ and the current class turns out to be the last one in the
    MRO that has it.

    In short, if you're using super and don't feel burdened by it, then
    you're probably using it incorrectly.
    The truth is that for multiple inheritance, you better be using super or
    your code is probably buggy (unless you manually duplicate what super
    does for you).
    No. For diamond inheritance, you better be using super or your code
    is probably buggy. For typical diamond-less multiple inheritance,
    super is both unnecessary and tricky to use correctly.
    And for single inheritance, it makes no difference whether
    you use super or not.
    Right. It's unnecessary, so why saddle yourself with it?
  • Raymond Hettinger at May 25, 2011 at 11:45 pm

    On May 25, 4:31?pm, Ian Kelly wrote:
    Right. ?It's unnecessary, so why saddle yourself with it?
    FWIW, I expect to release a blog post tomorrow about the principal use
    cases for super() and how to use it effectively.

    With just a little bit of know-how, it can be an important tool in
    your Python toolkit.

    If any of the comp.lang.python readers want to review and comment on
    my latest draft, please email me and I'll send it to you directly.

    Cheers,


    Raymond Hettinger

    my email address is listed at http://users.rcn.com/python/download/Descriptor.htm
  • Carl Banks at May 25, 2011 at 11:26 pm

    On Wednesday, May 25, 2011 10:54:11 AM UTC-7, Jess Austin wrote:
    I may be attempting something improper here, but maybe I'm just going
    about it the wrong way. I'm subclassing
    http.server.CGIHTTPRequestHandler, and I'm using a decorator to add
    functionality to several overridden methods.

    def do_decorate(func):
    . def wrapper(self):
    . if appropriate():
    . return func()
    . complain_about_error()
    . return wrapper

    class myHandler(CGIHTTPRequestHandler):
    . @do_decorate
    . def do_GET(self):
    . return super().do_GET()
    . # also override do_HEAD and do_POST

    My first thought was that I could just replace that whole method
    definition with one line:

    class myHandler(CGIHTTPRequestHandler):
    . do_GET = do_decorate(super().do_GET)

    That generates the following error:

    SystemError: super(): __class__ cell not found

    So I guess that when super() is called in the context of a class def
    rather than that of a method def, it doesn't have the information it
    needs.
    Right. Actually the class object itself doesn't even exist yet when super() is invoked. (It won't be created until after the end of the class statement block.)
    Now I'll probably just say:

    do_GET = do_decorate(CGIHTTPRequestHandler.do_GET)

    but I wonder if there is a "correct" way to do this instead? Thanks!
    Well, since the class object isn't created until after the end of the class statement block, it's impossible to invoke super() on the class from inside the block. So there's only two ways to invoke super(): 1. like you did above, by calling it inside a method, and 2. call it beyond the end of the class statement, like this:

    class myHandler(CGIHTTPRequestHandler):
    pass

    myHandler.do_GET = do_decorate(super(myHandler).do_GET)

    I wouldn't call that correct, though. (I'm not even sure it'll work, since I don't have Python 3 handy to test it, but as far as I can tell it will.)

    It's just one of the quirks of Python's type system.

    I don't agree with Ian's recommendation not to use super() in general, but I'd probably agree that one should stick to using it only in its intended way (to invoke base-class methods directly).


    Carl Banks

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
grouppython-list @
categoriespython
postedMay 25, '11 at 5:54p
activeMay 25, '11 at 11:45p
posts7
users6
websitepython.org

People

Translate

site design / logo © 2022 Grokbase