Pb with descriptor and super ...

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

    #1

    Pb with descriptor and super ...

    Hi all,

    I have a problem with the use of descriptors
    and super. The file is :

    # ---------------

    class Desc(object):
    def __init__(self, class_name):
    self.class_name = class_name
    return
    def __get__(self, obj, typ):
    print "Desc.__get __ : class_name is %s, obj is %s and typ is
    %s"%(self.class _name, obj, typ)
    return
    pass

    class A(object):
    attr = Desc("A")
    pass

    class B(A):
    attr = Desc("B")
    pass

    b = B()

    print "-------"
    print "Getting b.attr ..."
    print "I hope that : class_name is B, obj is b and typ is B"
    b.attr
    print "-------"
    print "Getting super(B, b).attr ..."
    print "I hope that : class_name is A, obj is b and typ is A but it is
    not the case !"
    super(B, b).attr
    print "-------"

    # -----------

    and the result is :

    -------
    Getting b.attr ...
    I hope that : class_name is B, obj is b and typ is B
    Desc.__get__ : class_name is B, obj is <__main__.B object at 0xb7b1f8ec>
    and typ is <class '__main__.B'>
    -------
    Getting super(B, b).attr ...
    I hope that : class_name is A, obj is b and typ is A but it is not the
    case !
    Desc.__get__ : class_name is A, obj is <__main__.B object at 0xb7b1f8ec>
    and typ is <class '__main__.B'>
    -------

    I expected that when getting super(B, b).attr, typ is A, but it is not
    the case ...

    python used :

    [adam@is111902 /home/adam/Work/Python]python
    Python 2.4.3 (#2, Sep 18 2006, 21:07:35)
    [GCC 4.1.1 20060724 (prerelease) (4.1.1-3mdk)] on linux2
    Type "help", "copyright" , "credits" or "license" for more information.
    >>>

    Best regards,


    E.A.
  • Gabriel Genellina

    #2
    Re: Pb with descriptor and super ...

    En Fri, 09 Mar 2007 06:25:08 -0300, Erwan Adam <erwan.adam@cea .fr>
    escribió:
    I have a problem with the use of descriptors
    and super. The file is :
    Descriptors for "super" behave a bit different than for classes. See


    --
    Gabriel Genellina

    Comment

    • Erwan Adam

      #3
      Re: Pb with descriptor and super ...

      Erwan Adam a écrit :
      Hi all,
      >
      I have a problem with the use of descriptors
      and super. The file is :
      >
      # ---------------
      >
      class Desc(object):
      def __init__(self, class_name):
      self.class_name = class_name
      return
      def __get__(self, obj, typ):
      print "Desc.__get __ : class_name is %s, obj is %s and typ is
      %s"%(self.class _name, obj, typ)
      return
      pass
      >
      class A(object):
      attr = Desc("A")
      pass
      >
      class B(A):
      attr = Desc("B")
      pass
      >
      b = B()
      >
      print "-------"
      print "Getting b.attr ..."
      print "I hope that : class_name is B, obj is b and typ is B"
      b.attr
      print "-------"
      print "Getting super(B, b).attr ..."
      print "I hope that : class_name is A, obj is b and typ is A but it is
      not the case !"
      super(B, b).attr
      print "-------"
      >
      # -----------
      >
      and the result is :
      >
      -------
      Getting b.attr ...
      I hope that : class_name is B, obj is b and typ is B
      Desc.__get__ : class_name is B, obj is <__main__.B object at 0xb7b1f8ec>
      and typ is <class '__main__.B'>
      -------
      Getting super(B, b).attr ...
      I hope that : class_name is A, obj is b and typ is A but it is not the
      case !
      Desc.__get__ : class_name is A, obj is <__main__.B object at 0xb7b1f8ec>
      and typ is <class '__main__.B'>
      -------
      >
      I expected that when getting super(B, b).attr, typ is A, but it is not
      the case ...
      Moreover, on the page :



      the author writes :

      "The call super(B, obj).m() searches obj.__class__._ _mro__ for the base
      class A immediately following B and then returns
      A.__dict__['m'].__get__(obj, A)."

      which it seems not the case ...

      Is it a bug or a mis-understood ?

      Regards,

      E.A.

      >
      python used :
      >
      [adam@is111902 /home/adam/Work/Python]python
      Python 2.4.3 (#2, Sep 18 2006, 21:07:35)
      [GCC 4.1.1 20060724 (prerelease) (4.1.1-3mdk)] on linux2
      Type "help", "copyright" , "credits" or "license" for more information.
      >>>
      >
      >
      Best regards,
      >
      >
      E.A.

      Comment

      • Erwan Adam

        #4
        Re: Pb with descriptor and super ...

        Gabriel Genellina a écrit :
        En Fri, 09 Mar 2007 06:25:08 -0300, Erwan Adam <erwan.adam@cea .fr>
        escribió:
        >
        >I have a problem with the use of descriptors
        >and super. The file is :
        >
        Descriptors for "super" behave a bit different than for classes. See

        >
        --Gabriel Genellina
        >
        Hi Gabriel,

        Thanks for your answer ... I followed the link
        and tried to use the "fully functional implementation of
        the super() built-in class in pure Python" given
        on this page and the result is quite surprising :

        # -------------

        class Super(object):
        def __init__(self, type, obj=None):
        self.__type__ = type
        self.__obj__ = obj
        def __get__(self, obj, type=None):
        if self.__obj__ is None and obj is not None:
        return Super(self.__ty pe__, obj)
        else:
        return self
        def __getattr__(sel f, attr):
        if isinstance(self .__obj__, self.__type__):
        starttype = self.__obj__.__ class__
        else:
        starttype = self.__obj__
        mro = iter(starttype. __mro__)
        for cls in mro:
        if cls is self.__type__:
        break
        # Note: mro is an iterator, so the second loop
        # picks up where the first one left off!
        for cls in mro:
        if attr in cls.__dict__:
        x = cls.__dict__[attr]
        if hasattr(x, "__get__"):
        x = x.__get__(self. __obj__)
        return x
        raise AttributeError, attr

        class Desc(object):
        def __init__(self, class_name):
        self.class_name = class_name
        return
        def __get__(self, obj, typ=None):
        print "Desc.__get __ : class_name is %s, obj is %s and typ is
        %s"%(self.class _name, obj, typ)
        return
        pass

        class A(object):
        attr = Desc("A")
        pass

        class B(A):
        attr = Desc("B")
        pass

        b = B()

        print "Using built-in super"
        attr = super(B, b).attr
        print "Using python Super"
        attr = Super(B, b).attr

        class MySuper(object) :
        def __init__(self, type, obj=None):
        self.__type__ = type
        self.__obj__ = obj
        def __get__(self, obj, type=None):
        if self.__obj__ is None and obj is not None:
        return Super(self.__ty pe__, obj)
        else:
        return self
        def __getattr__(sel f, attr):
        if isinstance(self .__obj__, self.__type__):
        starttype = self.__obj__.__ class__
        else:
        starttype = self.__obj__
        mro = iter(starttype. __mro__)
        for cls in mro:
        if cls is self.__type__:
        break
        # Note: mro is an iterator, so the second loop
        # picks up where the first one left off!
        for cls in mro:
        if attr in cls.__dict__:
        x = cls.__dict__[attr]
        if hasattr(x, "__get__"):
        x = x.__get__(self. __obj__, cls)
        return x
        raise AttributeError, attr

        print "Using python MySuper"
        attr = MySuper(B, b).attr


        # ------------------------------

        it gives :

        [adam@is111902 /home/adam/Work/Python]python super_from_guid o.py
        Using built-in super
        Desc.__get__ : class_name is A, obj is <__main__.B object at 0xb7bc302c>
        and typ is <class '__main__.B'>
        Using python Super
        Desc.__get__ : class_name is A, obj is <__main__.B object at 0xb7bc302c>
        and typ is None
        Using python MySuper
        Desc.__get__ : class_name is A, obj is <__main__.B object at 0xb7bc302c>
        and typ is <class '__main__.A'>

        the Super gives None for typ ... which is quite surprising !
        In MySuper, I just change

        x = x.__get__(self. __obj__)

        by

        x = x.__get__(self. __obj__, cls)

        at the -3 :) line of the class ... and it gives the result I expected
        at the beginning : obj is b and typ is A !!!!


        Best regards,

        E.A.

        Comment

        • Gabriel Genellina

          #5
          Re: Pb with descriptor and super ...

          En Fri, 09 Mar 2007 08:22:46 -0300, Erwan Adam <erwan.adam@cea .fr>
          escribió:
          Thanks for your answer ... I followed the link
          and tried to use the "fully functional implementation of
          the super() built-in class in pure Python" given
          on this page and the result is quite surprising :
          It appears that there is some disagreement on how the super object should
          behave.
          If you want to know what it actually *does* now (not what it *should* do)
          you can look at typeobject.c, but it's a bit hard to read, and I don't
          understand it in full...
          Maybe looking at the test suite is easier, in test_descr.py

          --
          Gabriel Genellina

          Comment

          • Arnaud Delobelle

            #6
            Re: Pb with descriptor and super ...

            On Mar 9, 11:22 am, Erwan Adam <erwan.a...@cea .frwrote:
            [snip]
            >
            [adam@is111902 /home/adam/Work/Python]python super_from_guid o.py
            Using built-in super
            Desc.__get__ : class_name is A, obj is <__main__.B object at 0xb7bc302c>
            and typ is <class '__main__.B'>
            Using python Super
            Desc.__get__ : class_name is A, obj is <__main__.B object at 0xb7bc302c>
            and typ is None
            Using python MySuper
            Desc.__get__ : class_name is A, obj is <__main__.B object at 0xb7bc302c>
            and typ is <class '__main__.A'>
            It seems to me that it is the built-in super which has the correct
            behaviour. When you write obj.attr, python calls attr.__get__(ob j,
            type(obj)) and not attr.__get__(ob j) which sets the second arg to
            None. You can check this by creating a barebone descriptor that simply
            prints its arguments:

            class D(object):
            def __get__(self, obj, objtype):
            print obj, objtype

            class A(object):
            d=D()

            A().d
            <__main__.A object at 0x133c5f0<class '__main__.A'# objtype is not
            None!

            Therefore in your case when you do super(B, b).attr then
            A.__dict__['attr'].__get__(b, type(b)) is called. You can try this, it
            should give the same output as builtin super.
            the Super gives None for typ ... which is quite surprising !
            In MySuper, I just change
            >
            x = x.__get__(self. __obj__)
            >
            by
            >
            x = x.__get__(self. __obj__, cls)
            at the -3 :) line of the class ... and it gives the result I expected
            at the beginning : obj is b and typ is A !!!!
            Neither of these are right I think. If my explanation above is right
            the correct line should be:
            x = x.__get__(self. __obj__, type(self.__obj __))

            HTH

            --
            Arnaud

            Comment

            Working...