instance attributes not inherited?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • John M. Gabriele

    #1

    instance attributes not inherited?

    The following short program fails:


    ----------------------- code ------------------------
    #!/usr/bin/python

    class Parent( object ):
    def __init__( self ):
    self.x = 9
    print "Inside Parent.__init__ ()"


    class Child( Parent ):
    def __init__( self ):
    print "Inside Child.__init__( )"


    p1 = Parent()
    p2 = Parent()
    c1 = Child()
    foo = [p1,p2,c1]

    for i in foo:
    print "x =", i.x
    ----------------- /code ----------------------



    yielding the following output:

    ---------------- output ------------------
    Inside Parent.__init__ ()
    Inside Parent.__init__ ()
    Inside Child.__init__( )
    x = 9
    x = 9
    x =
    Traceback (most recent call last):
    File "./foo.py", line 21, in ?
    print "x =", i.x
    AttributeError: 'Child' object has no attribute 'x'
    ---------------- /output ---------------------


    Why isn't the instance attribute x getting inherited?

    My experience with OOP has been with C++ and (more
    recently) Java. If I create an instance of a Child object,
    I expect it to *be* a Parent object (just as, if I subclass
    a Car class to create a VW class, I expect all VW's to *be*
    Cars).

    That is to say, if there's something a Parent can do, shouldn't
    the Child be able to do it too? Consider a similar program:

    ------------------- code ------------------------
    #!/usr/bin/python


    class Parent( object ):
    def __init__( self ):
    self.x = 9
    print "Inside Parent.__init__ ()"

    def wash_dishes( self ):
    print "Just washed", self.x, "dishes."


    class Child( Parent ):
    def __init__( self ):
    print "Inside Child.__init__( )"


    p1 = Parent()
    p2 = Parent()
    c1 = Child()
    foo = [p1,p2,c1]

    for i in foo:
    i.wash_dishes()
    ------------------- /code -----------------------

    But that fails with:

    ------------------- output ----------------------
    Inside Parent.__init__ ()
    Inside Parent.__init__ ()
    Inside Child.__init__( )
    Just washed 9 dishes.
    Just washed 9 dishes.
    Just washed
    Traceback (most recent call last):
    File "./foo.py", line 24, in ?
    i.wash_dishes()
    File "./foo.py", line 10, in wash_dishes
    print "Just washed", self.x, "dishes."
    AttributeError: 'Child' object has no attribute 'x'
    ------------------- /output ---------------------

    Why isn't this inherited method call working right?
    Is this a problem with Python's notion of how OO works?

    Thanks,
    ---J

    --
    (remove zeez if demunging email address)
  • David Hirschfield

    #2
    Re: instance attributes not inherited?

    Nothing's wrong with python's oop inheritance, you just need to know
    that the parent class' __init__ is not automatically called from a
    subclass' __init__. Just change your code to do that step, and you'll be
    fine:

    class Parent( object ):
    def __init__( self ):
    self.x = 9


    class Child( Parent ):
    def __init__( self ):
    super(Child,sel f).__init__()
    print "Inside Child.__init__( )"

    -David

    John M. Gabriele wrote:
    [color=blue]
    >The following short program fails:
    >
    >
    >----------------------- code ------------------------
    >#!/usr/bin/python
    >
    >class Parent( object ):
    > def __init__( self ):
    > self.x = 9
    > print "Inside Parent.__init__ ()"
    >
    >
    >class Child( Parent ):
    > def __init__( self ):
    > print "Inside Child.__init__( )"
    >
    >
    >p1 = Parent()
    >p2 = Parent()
    >c1 = Child()
    >foo = [p1,p2,c1]
    >
    >for i in foo:
    > print "x =", i.x
    >----------------- /code ----------------------
    >
    >
    >
    >yielding the following output:
    >
    >---------------- output ------------------
    >Inside Parent.__init__ ()
    >Inside Parent.__init__ ()
    >Inside Child.__init__( )
    >x = 9
    >x = 9
    >x =
    >Traceback (most recent call last):
    > File "./foo.py", line 21, in ?
    > print "x =", i.x
    >AttributeError : 'Child' object has no attribute 'x'
    >---------------- /output ---------------------
    >
    >
    >Why isn't the instance attribute x getting inherited?
    >
    >My experience with OOP has been with C++ and (more
    >recently) Java. If I create an instance of a Child object,
    >I expect it to *be* a Parent object (just as, if I subclass
    >a Car class to create a VW class, I expect all VW's to *be*
    >Cars).
    >
    >That is to say, if there's something a Parent can do, shouldn't
    >the Child be able to do it too? Consider a similar program:
    >
    >------------------- code ------------------------
    >#!/usr/bin/python
    >
    >
    >class Parent( object ):
    > def __init__( self ):
    > self.x = 9
    > print "Inside Parent.__init__ ()"
    >
    > def wash_dishes( self ):
    > print "Just washed", self.x, "dishes."
    >
    >
    >class Child( Parent ):
    > def __init__( self ):
    > print "Inside Child.__init__( )"
    >
    >
    >p1 = Parent()
    >p2 = Parent()
    >c1 = Child()
    >foo = [p1,p2,c1]
    >
    >for i in foo:
    > i.wash_dishes()
    >------------------- /code -----------------------
    >
    >But that fails with:
    >
    >------------------- output ----------------------
    >Inside Parent.__init__ ()
    >Inside Parent.__init__ ()
    >Inside Child.__init__( )
    >Just washed 9 dishes.
    >Just washed 9 dishes.
    >Just washed
    >Traceback (most recent call last):
    > File "./foo.py", line 24, in ?
    > i.wash_dishes()
    > File "./foo.py", line 10, in wash_dishes
    > print "Just washed", self.x, "dishes."
    >AttributeError : 'Child' object has no attribute 'x'
    >------------------- /output ---------------------
    >
    >Why isn't this inherited method call working right?
    >Is this a problem with Python's notion of how OO works?
    >
    >Thanks,
    >---J
    >
    >
    >[/color]

    --
    Presenting:
    mediocre nebula.

    Comment

    • John M. Gabriele

      #3
      Re: instance attributes not inherited?

      David Hirschfield wrote:[color=blue]
      > Nothing's wrong with python's oop inheritance, you just need to know
      > that the parent class' __init__ is not automatically called from a
      > subclass' __init__. Just change your code to do that step, and you'll be
      > fine:
      >
      > class Parent( object ):
      > def __init__( self ):
      > self.x = 9
      >
      >
      > class Child( Parent ):
      > def __init__( self ):
      > super(Child,sel f).__init__()
      > print "Inside Child.__init__( )"
      >
      > -David
      >[/color]

      How does it help that Parent.__init__ gets called? That call simply
      would create a temporary Parent object, right? I don't see how it
      should help (even though it *does* indeed work).

      Why do we need to pass self along in that call to super()? Shouldn't
      the class name be enough for super() to find the right superclass object?

      Comment

      • John M. Gabriele

        #4
        Re: instance attributes not inherited?

        John M. Gabriele wrote:[color=blue]
        > David Hirschfield wrote:
        >[color=green]
        >> Nothing's wrong with python's oop inheritance, you just need to know
        >> that the parent class' __init__ is not automatically called from a
        >> subclass' __init__. Just change your code to do that step, and you'll
        >> be fine:
        >>
        >> class Parent( object ):
        >> def __init__( self ):
        >> self.x = 9
        >>
        >>
        >> class Child( Parent ):
        >> def __init__( self ):
        >> super(Child,sel f).__init__()
        >> print "Inside Child.__init__( )"
        >>
        >> -David
        >>[/color]
        >
        > How does it help that Parent.__init__ gets called? That call simply
        > would create a temporary Parent object, right? I don't see how it
        > should help (even though it *does* indeed work).[/color]

        Sorry -- that question I wrote looks a little incomplete: what I meant
        to ask was, how does it help this code to work:

        ---- code ----
        #!/usr/bin/python

        class Parent( object ):
        def __init__( self ):
        self.x = 9
        print "Inside Parent.__init__ ()"

        def wash_dishes( self ):
        print "Inside Parent.wash_dis hes(), washing", self.x, "dishes."


        class Child( Parent ):
        def __init__( self ):
        super( Child, self ).__init__()
        print "Inside Child.__init__( )"


        c = Child()
        c.wash_dishes()
        ---- /code ----

        since the x instance attribute created during the
        super( Child, self ).__init__() call is just part of what looks to be
        a temporary Parent instance.




        --
        (remove zeez if demunging email address)

        Comment

        • Bengt Richter

          #5
          Re: instance attributes not inherited?

          On Sun, 15 Jan 2006 18:44:50 -0500, "John M. Gabriele" <john_sips_teaz @yahooz.com> wrote:
          [color=blue]
          >The following short program fails:[/color]
          to do what you intended, but it does not fail to do what you programmed ;-)[color=blue]
          >
          >
          >----------------------- code ------------------------
          >#!/usr/bin/python
          >
          >class Parent( object ):
          > def __init__( self ):
          > self.x = 9
          > print "Inside Parent.__init__ ()"
          >
          >
          >class Child( Parent ):
          > def __init__( self ):
          > print "Inside Child.__init__( )"
          >
          >
          >p1 = Parent()
          >p2 = Parent()
          >c1 = Child()
          >foo = [p1,p2,c1]
          >
          >for i in foo:
          > print "x =", i.x
          >----------------- /code ----------------------
          >
          >
          >
          >yielding the following output:
          >
          >---------------- output ------------------
          >Inside Parent.__init__ ()
          >Inside Parent.__init__ ()
          >Inside Child.__init__( )
          >x = 9
          >x = 9
          >x =
          >Traceback (most recent call last):
          > File "./foo.py", line 21, in ?
          > print "x =", i.x
          >AttributeError : 'Child' object has no attribute 'x'
          >---------------- /output ---------------------
          >
          >
          >Why isn't the instance attribute x getting inherited?[/color]
          It would be if it existed, but your Child defines __init__
          and that overrides the Parent __init__, so since you do not
          call Parent.__init__ (directly or by way of super), x does not get set,
          and there is nothing to "inherit".

          BTW, "inherit" is not really what makes x visible as an attribute of the
          instance in this case. The x attribute happens to be assigned in Parent.__init__ ,
          but that does not make it an inherited attribute of Parent. IOW, Parent.__init__
          is a function that becomes bound to the instance and then operates on the instance
          to set the instance's x attribute, but any function could do that. Or any statement
          with access to the instance in some way could do it. Inheritance would be if there were
          e.g. a Parent.x class variable or property. Then Child().x would find that by inheritance.

          BTW, if you did _not_ define Child.__init__ at all, Child would inherit Parent.__init__
          and it would be called, and would set the x attribute on the child instance.
          [color=blue]
          >
          >My experience with OOP has been with C++ and (more
          >recently) Java. If I create an instance of a Child object,
          >I expect it to *be* a Parent object (just as, if I subclass
          >a Car class to create a VW class, I expect all VW's to *be*
          >Cars).
          >
          >That is to say, if there's something a Parent can do, shouldn't
          >the Child be able to do it too? Consider a similar program:
          >
          >------------------- code ------------------------
          >#!/usr/bin/python
          >
          >
          >class Parent( object ):
          > def __init__( self ):
          > self.x = 9
          > print "Inside Parent.__init__ ()"
          >
          > def wash_dishes( self ):
          > print "Just washed", self.x, "dishes."
          >
          >
          >class Child( Parent ):
          > def __init__( self ):
          > print "Inside Child.__init__( )"
          >
          >
          >p1 = Parent()
          >p2 = Parent()
          >c1 = Child()
          >foo = [p1,p2,c1]
          >
          >for i in foo:
          > i.wash_dishes()
          >------------------- /code -----------------------
          >
          >But that fails with:
          >
          >------------------- output ----------------------
          >Inside Parent.__init__ ()
          >Inside Parent.__init__ ()
          >Inside Child.__init__( )
          >Just washed 9 dishes.
          >Just washed 9 dishes.
          >Just washed
          >Traceback (most recent call last):
          > File "./foo.py", line 24, in ?
          > i.wash_dishes()
          > File "./foo.py", line 10, in wash_dishes
          > print "Just washed", self.x, "dishes."
          >AttributeError : 'Child' object has no attribute 'x'
          >------------------- /output ---------------------
          >
          >Why isn't this inherited method call working right?[/color]
          The method call is working fine. It's just that as before
          Child.__init__ overrides Parent.__init__ without calling
          Parent.__init__ or setting the x attribute itself, so
          "AttributeError : 'Child' object has no attribute 'x'"
          is telling the truth. And it's telling that was discovered
          at "File "./foo.py", line 10, in wash_dishes" -- in other
          words _inside_ wash_dishes, meaning the call worked, but
          you hadn't provided for the initialization of the x attribute
          it depended on.

          There are various ways to fix this besides calling Parent.__init__
          from Child.__init__, depending on desired semantics.
          [color=blue]
          >Is this a problem with Python's notion of how OO works?[/color]
          Nope ;-)

          Regards,
          Bengt Richter

          Comment

          • Dan Sommers

            #6
            Re: instance attributes not inherited?

            On Sun, 15 Jan 2006 20:37:36 -0500,
            "John M. Gabriele" <john_sips_teaz @yahooz.com> wrote:
            [color=blue]
            > David Hirschfield wrote:[/color]
            [color=blue][color=green]
            >> Nothing's wrong with python's oop inheritance, you just need to know
            >> that the parent class' __init__ is not automatically called from a
            >> subclass' __init__. Just change your code to do that step, and you'll
            >> be fine:[/color][/color]

            [example snipped]
            [color=blue]
            > How does it help that Parent.__init__ gets called? That call simply
            > would create a temporary Parent object, right? I don't see how it
            > should help (even though it *does* indeed work).[/color]

            The __init__ method is an *initializer*, *not* a constructor. By the
            time __init__ runs, the object has already been constructed; __init__
            just does extra initialization.

            Regards,
            Dan

            --
            Dan Sommers
            <http://www.tombstoneze ro.net/dan/>

            Comment

            • John M. Gabriele

              #7
              Re: instance attributes not inherited?

              Dan Sommers wrote:[color=blue]
              > [snip]
              >[color=green]
              >>How does it help that Parent.__init__ gets called? That call simply
              >>would create a temporary Parent object, right? I don't see how it
              >>should help (even though it *does* indeed work).[/color]
              >
              >
              > The __init__ method is an *initializer*, *not* a constructor. By the
              > time __init__ runs, the object has already been constructed; __init__
              > just does extra initialization.
              >
              > Regards,
              > Dan
              >[/color]

              Right. Thanks for the clarification. :)

              --
              (remove zeez if demunging email address)

              Comment

              • John M. Gabriele

                #8
                Re: instance attributes not inherited?

                Dennis Lee Bieber wrote:[color=blue]
                > On Sun, 15 Jan 2006 20:50:59 -0500, "John M. Gabriele"
                > <john_sips_teaz @yahooz.com> declaimed the following in comp.lang.pytho n:
                >
                >[color=green]
                >>Sorry -- that question I wrote looks a little incomplete: what I meant
                >>to ask was, how does it help this code to work:
                >>
                >>---- code ----
                >>#!/usr/bin/python
                >>
                >>class Parent( object ):
                >> def __init__( self ):
                >> self.x = 9
                >> print "Inside Parent.__init__ ()"
                >>
                >> def wash_dishes( self ):
                >> print "Inside Parent.wash_dis hes(), washing", self.x, "dishes."
                >>
                >>
                >>class Child( Parent ):
                >> def __init__( self ):
                >> super( Child, self ).__init__()
                >> print "Inside Child.__init__( )"
                >>
                >>
                >>c = Child()
                >>c.wash_dishes ()
                >>---- /code ----
                >>
                >>since the x instance attribute created during the
                >>super( Child, self ).__init__() call is just part of what looks to be
                >>a temporary Parent instance.[/color][/color]

                (Whoops. I see now thanks to Dan Sommers' comment that there's
                no temp Parent instance, unless the call to super() is creating
                one...)
                [color=blue]
                >
                > Because you passed the CHILD INSTANCE (self) to the method of the
                > super... so "self.x" is "child-instance.x"[/color]

                Huh? But it sounds by the name of it that super() is supposed to
                return something like the superclass (i.e. Parent). You mean, that
                super( Child, self ).__init__() call inside Child.__init__( ) leads
                to Parent.__init__ () getting called but with the 'self' reference
                inside there referring to the Child object we named 'c' instead of
                some Parent .... {confused}

                Wait a second. I can replace that super() call with simply

                Parent.__init__ ( self )

                and everything still works... and it looks to me that, indeed,
                I'm passing self in (which refers to the Child object), and that
                self gets used in that __init__() method of Parent's... Wow. I'd
                never seen/understood that before! We're using superclass initializers
                on subclasses that weren't around when the superclass was written!

                I'm having a hard time finding the documentation to the super() function.
                I checked the language reference ( http://docs.python.org/ref/ref.html )
                but didn't find it. Can someone please point me to the relevant docs on
                super?

                help( super ) doesn't give much info at all, except that super is actually
                a class, and calling it the way we are here returns a "bound super object",
                but I don't yet see what that means (though I know what bound methods are).

                Thanks,
                ---J

                --
                (remove zeez if demunging email address)

                Comment

                • Xavier Morel

                  #9
                  Re: instance attributes not inherited?

                  John M. Gabriele wrote:[color=blue]
                  > I'm having a hard time finding the documentation to the super() function.
                  > I checked the language reference ( http://docs.python.org/ref/ref.html )
                  > but didn't find it. Can someone please point me to the relevant docs on
                  > super?
                  >
                  > help( super ) doesn't give much info at all, except that super is actually
                  > a class, and calling it the way we are here returns a "bound super object",
                  > but I don't yet see what that means (though I know what bound methods are).
                  >[/color]

                  Super is a bit magic, quite complicated, and some people don't like it
                  (basically, super is mainly to be used in complex inheritance case with
                  diamond shape hierarchies and such, to automate the method resolution
                  order).

                  If you want to give a try at understanding "super", you should read
                  Guido's `Unifying types and classes in Python 2.2`, chapters on MRO,
                  super and cooperative methods
                  (http://www.python.org/2.2.3/descrintro.html#mro) (nb: you may also read
                  the rest of the document, it lists all the magic introduced in the
                  language with 2.2).

                  Comment

                  • Bengt Richter

                    #10
                    Re: instance attributes not inherited?

                    On Sun, 15 Jan 2006 20:37:36 -0500, "John M. Gabriele" <john_sips_teaz @yahooz.com> wrote:
                    [color=blue]
                    >David Hirschfield wrote:[color=green]
                    >> Nothing's wrong with python's oop inheritance, you just need to know
                    >> that the parent class' __init__ is not automatically called from a
                    >> subclass' __init__. Just change your code to do that step, and you'll be
                    >> fine:
                    >>
                    >> class Parent( object ):
                    >> def __init__( self ):
                    >> self.x = 9
                    >>
                    >>
                    >> class Child( Parent ):
                    >> def __init__( self ):
                    >> super(Child,sel f).__init__()[/color][/color]
                    Nit: Someone is posting with source using tabs ;-/ The above super should be indented from def.[color=blue][color=green]
                    >> print "Inside Child.__init__( )"
                    >>
                    >> -David
                    >>[/color]
                    >
                    >How does it help that Parent.__init__ gets called? That call simply
                    >would create a temporary Parent object, right? I don't see how it[/color]
                    Wrong ;-) Calling __init__ does not create the object, it operates on an
                    object that has already been created. There is nothing special about
                    a user-written __init__ method other than the name and that is is automatically
                    invoked under usual conditions. Child.__new__ is the method that creates the instance,
                    but since Child doesn't have that method, it gets it by inheritance from Parent, which
                    in turn doesn't have one, so it inherits it from its base class (object).
                    [color=blue]
                    >should help (even though it *does* indeed work).
                    >
                    >Why do we need to pass self along in that call to super()? Shouldn't
                    >the class name be enough for super() to find the right superclass object?[/color]
                    self is the instance that needs to appear as the argument of the __init__ call,
                    so it has to come from somewhere. Actually, it would make more sense to leave out
                    the class than to leave out self, since you can get the class from type(self) for
                    typical super usage (see custom simple_super at end below [1])
                    [color=blue][color=green][color=darkred]
                    >>> class Parent( object ):[/color][/color][/color]
                    ... def __init__( self ):
                    ... self.x = 9
                    ... print 'Inside Parent.__init__ ()'
                    ...[color=blue][color=green][color=darkred]
                    >>> class Child( Parent ):[/color][/color][/color]
                    ... def __init__( self ):
                    ... sup = super(Child,sel f)
                    ... sup.__init__()
                    ... self.sup = sup
                    ... print "Inside Child.__init__( )"
                    ...[color=blue][color=green][color=darkred]
                    >>> c = Child()[/color][/color][/color]
                    Inside Parent.__init__ ()
                    Inside Child.__init__( )[color=blue][color=green][color=darkred]
                    >>> c.sup[/color][/color][/color]
                    <super: <class 'Child'>, <Child object>>

                    sup is an object that will present an attribute namespace that it implements
                    by looking for attributes in the inheritance hierarchy of the instance argument (child)
                    but starting one step beyond the normal first place to look, which is the instance's class
                    that was passed to super. For a normal method such as __init__, it will form the bound method
                    when you evaluate the __init__ attribute of the super object:
                    [color=blue][color=green][color=darkred]
                    >>> c.sup.__init__[/color][/color][/color]
                    <bound method Child.__init__ of <__main__.Chi ld object at 0x02EF3AAC>>

                    a bound method has the first argument bound in, and when you call the bound method
                    without an argument, the underlying function gets called with the actual first argument (self).
                    [color=blue][color=green][color=darkred]
                    >>> c.sup.__init__( )[/color][/color][/color]
                    Inside Parent.__init__ ()

                    The method resolution order lists the base classes of a particular class in the order they
                    will be searched for a method. super skips the current class, since it is shadowing the rest.
                    The whole list:
                    [color=blue][color=green][color=darkred]
                    >>> type(c).mro()[/color][/color][/color]
                    [<class '__main__.Child '>, <class '__main__.Paren t'>, <type 'object'>]

                    Skipping to where super will start looking:[color=blue][color=green][color=darkred]
                    >>> type(c).mro()[1][/color][/color][/color]
                    <class '__main__.Paren t'>

                    If you get the __init__ attribute from the class, as opposed to as an
                    attribute of the instance, you get an UNbound method:
                    [color=blue][color=green][color=darkred]
                    >>> type(c).mro()[1].__init__[/color][/color][/color]
                    <unbound method Parent.__init__ >

                    which can be called with the instance as the first argument:
                    [color=blue][color=green][color=darkred]
                    >>> type(c).mro()[1].__init__(c)[/color][/color][/color]
                    Inside Parent.__init__ ()

                    If you want to, you can access the actual function behind the unbound method:
                    [color=blue][color=green][color=darkred]
                    >>> type(c).mro()[1].__init__.im_fu nc[/color][/color][/color]
                    <function __init__ at 0x02EEADBC>

                    And form a bound method:
                    [color=blue][color=green][color=darkred]
                    >>> type(c).mro()[1].__init__.im_fu nc.__get__(c, type(c))[/color][/color][/color]
                    <bound method Child.__init__ of <__main__.Chi ld object at 0x02EF3AAC>>

                    Which you can then call, just like we did sup.__init__ above:
                    [color=blue][color=green][color=darkred]
                    >>> type(c).mro()[1].__init__.im_fu nc.__get__(c, type(c))()[/color][/color][/color]
                    Inside Parent.__init__ ()


                    Another way to spell this is:
                    [color=blue][color=green][color=darkred]
                    >>> Parent.__init__ .im_func[/color][/color][/color]
                    <function __init__ at 0x02EEADBC>[color=blue][color=green][color=darkred]
                    >>> Parent.__init__ .im_func.__get_ _(c, type(c))[/color][/color][/color]
                    <bound method Child.__init__ of <__main__.Chi ld object at 0x02EF3AAC>>[color=blue][color=green][color=darkred]
                    >>> Parent.__init__ .im_func.__get_ _(c, type(c))()[/color][/color][/color]
                    Inside Parent.__init__ ()

                    Or without forming the unbound method and using im_func to
                    get the function (looking instead for the __init__ function per se in the Parent class dict):
                    [color=blue][color=green][color=darkred]
                    >>> Parent.__dict__['__init__'][/color][/color][/color]
                    <function __init__ at 0x02EEADBC>[color=blue][color=green][color=darkred]
                    >>> Parent.__dict__['__init__'].__get__(c, type(c))[/color][/color][/color]
                    <bound method Child.__init__ of <__main__.Chi ld object at 0x02EF3AAC>>[color=blue][color=green][color=darkred]
                    >>> Parent.__dict__['__init__'].__get__(c, type(c))()[/color][/color][/color]
                    Inside Parent.__init__ ()

                    An attribute with a __get__ method (which any normal function has) is a
                    descriptor, and depending on various logic will have its __get__ method
                    called with the object whose attribute is apparently being accessed.
                    Much of python's magic is implemented via descriptors, so you may want
                    to read about it ;-)

                    [1] If we wanted to, we could write our own simple_super. E.g.,
                    [color=blue][color=green][color=darkred]
                    >>> class simple_super(ob ject):[/color][/color][/color]
                    ... def __init__(self, inst): self.inst = inst
                    ... def __getattribute_ _(self, attr):
                    ... inst = object.__getatt ribute__(self, 'inst')
                    ... try: return getattr(type(in st).mro()[1], attr).im_func._ _get__(
                    ... inst, type(inst))
                    ... except AttributeError:
                    ... return object.__getatt ribute__(self, attr)
                    ...[color=blue][color=green][color=darkred]
                    >>> class Parent( object ):[/color][/color][/color]
                    ... def __init__( self ):
                    ... self.x = 9
                    ... print 'Inside Parent.__init__ ()'
                    ...[color=blue][color=green][color=darkred]
                    >>> class Child( Parent ):[/color][/color][/color]
                    ... def __init__( self ):
                    ... sup = simple_super(se lf)
                    ... sup.__init__()
                    ... self.sup = sup
                    ... print "Inside Child.__init__( )"
                    ...[color=blue][color=green][color=darkred]
                    >>> c = Child()[/color][/color][/color]
                    Inside Parent.__init__ ()
                    Inside Child.__init__( )[color=blue][color=green][color=darkred]
                    >>> c.sup[/color][/color][/color]
                    <__main__.simpl e_super object at 0x02EF80EC>[color=blue][color=green][color=darkred]
                    >>> c.sup.__init__[/color][/color][/color]
                    <bound method Child.__init__ of <__main__.Chi ld object at 0x02EF80CC>>[color=blue][color=green][color=darkred]
                    >>> c.sup.__init__( )[/color][/color][/color]
                    Inside Parent.__init__ ()

                    I don't know if this helps ;-)

                    Regards,
                    Bengt Richter

                    Comment

                    • Duncan Booth

                      #11
                      Posting examples with tabs

                      Bengt Richter wrote:
                      [color=blue]
                      > Nit: Someone is posting with source using tabs[/color]

                      Which reminds me: can anyone tell me how to configure idle so that the
                      shell has tabs disabled by default?

                      The editor defaults to not using tabs, and I can toggle the setting from
                      the options dialog, but the shell has tab use turned on and so far as I can
                      see it is hardwired (it can be toggled at runtime, or I can edit PyShell.py
                      but I feel there ought to be a configuration setting to turn tabs off
                      only I can't find one).

                      Comment

                      Working...