Class extension confusion :(

Peter Otten __peter__ at web.de
Thu Nov 11 04:34:22 EST 2010


r0g wrote:

> On 10/11/10 09:52, Peter Otten wrote:
>> class PlainAJAXRequestHandler(BaseHTTPRequestHandler):
>>      def __init__(self, api_call, paths, *args, **kw):
>>          BaseHTTPRequestHandler.__init__(self, *args, **kw)
>>          self.api_call = api_call
>>          self.paths = paths
> 
> 
> Hmm, the plot thickens! I always thought you had to call the parent
> constructor first (as above) when extending a constructor (not that I've
> had occasion to do that in a long time), but it turns out when I do this
> the lines below it never get executed and when I move them above that
> line they seem to work fine so it appears I was wrong about that. I've

I didn't believe you until I had a look into the source. The meat is in
SocketServer.py:

class BaseRequestHandler:

[snip]

    def __init__(self, request, client_address, server):
        self.request = request
        self.client_address = client_address
        self.server = server
        try:
            self.setup()
            self.handle()
            self.finish()
        finally:
            sys.exc_traceback = None    # Help garbage collection

    def setup(self):
        pass

    def handle(self):
        pass

    def finish(self):
        pass


As you can see this doesn't use __init__() just to set up the instance, it 
makes it the only method that is called by client code. 

That's an unusual design decision, to say the least.

> tried typing many variants of "python class extend constructor" into
> google over the last few days but I'm damned if I can find the docs
> explaining this. I'm sure I found them several years back when I first
> too up python, maybe by google-fu is on the wane!
> 
> Anyway, that's not my main question, this is... The extra names that I
> pass to functools.partial seem to be bound permanently into the
> namespace of my class now i.e. I can reference them as 'api_call' and
> 'paths' anywhere in the classes' methods as opposed to having to assign
> them in the constructor and reference them as 'self.api_call' and
> 'self.paths'. I'm not 100% how that's working but in practical terms it
> suggests to two lines assigning those names to data attributes are
> redundant as I can access them anywhere anyway. Indeed, I've commented
> them out and my app still seems to work fine so...
> 
> Question A) Are there any good reasons why I shouldn't just do that?
> (other than B!)

No. Use either

class B(A):
   path = ...

or

class B(A):
    def __init__(self, path, *args, **kw):
        self.path = path
        A.__init__(self, *args, **kw)

not both.
 
> Question B) The only reason I can think of so far is that I don't have a
> clear picture of how those names came to end up in that scope, it seems
> very convenient but I'm worried it's black magic of some sort! Could
> anyone explain or point me to the right docs please?

Python looks for attributes in the instance first, and then in the class as 
a fallback. You only need to put them in the instance if you expect that you 
want a different value for every instance.

Peter




More information about the Python-list mailing list