Bypassing __setattr__ for changing special attributes

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

    #1

    Bypassing __setattr__ for changing special attributes

    I was kinda surprised that setting __class__ or __dict__ goes through
    the __setattr__ mechanism, like a normal attribute:

    class Foo(object):
    def __setattr__(sel f, attr, value):
    pass

    class Bar(object):
    pass
    >>f = Foo()
    >>f.__class__ = Bar
    >>print f.__class__ is Foo
    True

    Is there a way (even hackish) to bypass this, or at least achieve
    somehow the same goal (change f's class) ?

    George

  • Ziga Seilnacht

    #2
    Re: Bypassing __setattr__ for changing special attributes

    George Sakkis wrote:
    I was kinda surprised that setting __class__ or __dict__ goes through
    the __setattr__ mechanism, like a normal attribute:
    >
    class Foo(object):
    def __setattr__(sel f, attr, value):
    pass
    >
    class Bar(object):
    pass
    >
    >f = Foo()
    >f.__class__ = Bar
    >print f.__class__ is Foo
    True
    >
    Is there a way (even hackish) to bypass this, or at least achieve
    somehow the same goal (change f's class) ?
    >
    George
    >>object.__seta ttr__(f, '__class__', Bar)
    >>f.__class__ is Bar
    True

    Ziga

    Comment

    • bruno.desthuilliers@gmail.com

      #3
      Re: Bypassing __setattr__ for changing special attributes

      On 20 fév, 05:39, "George Sakkis" <george.sak...@ gmail.comwrote:
      I was kinda surprised that setting __class__ or __dict__ goes through
      the __setattr__ mechanism, like a normal attribute:
      But __class__ and __dict___ *are* 'normal' attributes...


      Comment

      • Steven D'Aprano

        #4
        Re: Bypassing __setattr__ for changing special attributes

        On Mon, 19 Feb 2007 23:18:02 -0800, Ziga Seilnacht wrote:
        George Sakkis wrote:
        >I was kinda surprised that setting __class__ or __dict__ goes through
        >the __setattr__ mechanism, like a normal attribute:
        >>
        >class Foo(object):
        > def __setattr__(sel f, attr, value):
        > pass
        >>
        >class Bar(object):
        > pass
        >>
        >>f = Foo()
        >>f.__class__ = Bar
        >>print f.__class__ is Foo
        >True
        >>
        >Is there a way (even hackish) to bypass this, or at least achieve
        >somehow the same goal (change f's class) ?
        >>
        >George
        >
        >>>object.__set attr__(f, '__class__', Bar)
        >>>f.__class_ _ is Bar
        True

        This version is arguably more "correct", although a tad longer to write,
        and doesn't need you to hard-code the class superclass:

        super(f.__class __, f).__setattr__( '__class__', Bar)


        But what surprised me was that this *didn't* work:
        >>f = Foo()
        >>f.__dict__['__class__'] = Bar
        >>f.__class__
        <class '__main__.Foo'>


        Unless I'm confused, it looks like instance.__clas s__ bypasses the usual
        lookup mechanism (instance.__dic t__, then instance.__clas s__.__dict__) for
        some reason.
        >>Foo.x = 1 # stored in class __dict__
        >>f.x
        1
        >>f.__dict__['x'] = 2 # stored in instance __dict__
        >>f.x
        2
        >>Foo.x
        1

        But __class__ doesn't behave like this. Why?



        --
        Steven.

        Comment

        • George Sakkis

          #5
          Re: Bypassing __setattr__ for changing special attributes

          On Feb 20, 3:54 am, "bruno.desthuil li...@gmail.com "
          <bruno.desthuil li...@gmail.com wrote:
          On 20 fév, 05:39, "George Sakkis" <george.sak...@ gmail.comwrote:
          >
          I was kinda surprised that setting __class__ or __dict__ goes through
          the __setattr__ mechanism, like a normal attribute:
          >
          But __class__ and __dict___ *are* 'normal' attributes...
          Well, let alone for the fact that two leading and trailing underscores
          means 'special' in python, these attributes are not exactly what they
          seem to be, i.e. a 'normal' type or dict:
          >>type(object._ _dict__['__class__'])
          <type 'getset_descrip tor'>
          >>type(type.__d ict__['__dict__'])
          <type 'getset_descrip tor'>


          George

          Comment

          • George Sakkis

            #6
            Re: Bypassing __setattr__ for changing special attributes

            On Feb 20, 7:57 am, Steven D'Aprano
            <s...@REMOVE.TH IS.cybersource. com.auwrote:
            On Mon, 19 Feb 2007 23:18:02 -0800, Ziga Seilnacht wrote:
            George Sakkis wrote:
            I was kinda surprised that setting __class__ or __dict__ goes through
            the __setattr__ mechanism, like a normal attribute:
            >
            class Foo(object):
            def __setattr__(sel f, attr, value):
            pass
            >
            class Bar(object):
            pass
            >
            >f = Foo()
            >f.__class__ = Bar
            >print f.__class__ is Foo
            True
            >
            Is there a way (even hackish) to bypass this, or at least achieve
            somehow the same goal (change f's class) ?
            >
            George
            >
            >>object.__seta ttr__(f, '__class__', Bar)
            >>f.__class__ is Bar
            True
            >
            This version is arguably more "correct", although a tad longer to write,
            and doesn't need you to hard-code the class superclass:
            >
            super(f.__class __, f).__setattr__( '__class__', Bar)
            >
            But what surprised me was that this *didn't* work:
            >
            >f = Foo()
            >f.__dict__['__class__'] = Bar
            >f.__class__
            >
            <class '__main__.Foo'>
            >
            Unless I'm confused, it looks like instance.__clas s__ bypasses the usual
            lookup mechanism (instance.__dic t__, then instance.__clas s__.__dict__) for
            some reason.
            >
            >Foo.x = 1 # stored in class __dict__
            >f.x
            1
            >f.__dict__['x'] = 2 # stored in instance __dict__
            >f.x
            2
            >Foo.x
            >
            1
            >
            But __class__ doesn't behave like this. Why?
            >
            --
            Steven.
            Perhaps because __class__ is a special descriptor:
            >>type(object._ _dict__['__class__'])
            <type 'getset_descrip tor'>

            George

            Comment

            • Fuzzyman

              #7
              Re: Bypassing __setattr__ for changing special attributes

              On Feb 20, 12:57 pm, Steven D'Aprano
              <s...@REMOVE.TH IS.cybersource. com.auwrote:
              On Mon, 19 Feb 2007 23:18:02 -0800, Ziga Seilnacht wrote:
              George Sakkis wrote:
              I was kinda surprised that setting __class__ or __dict__ goes through
              the __setattr__ mechanism, like a normal attribute:
              >
              class Foo(object):
              def __setattr__(sel f, attr, value):
              pass
              >
              class Bar(object):
              pass
              >
              >f = Foo()
              >f.__class__ = Bar
              >print f.__class__ is Foo
              True
              >
              Is there a way (even hackish) to bypass this, or at least achieve
              somehow the same goal (change f's class) ?
              >
              George
              >
              >>object.__seta ttr__(f, '__class__', Bar)
              >>f.__class__ is Bar
              True
              >
              This version is arguably more "correct", although a tad longer to write,
              and doesn't need you to hard-code the class superclass:
              >
              super(f.__class __, f).__setattr__( '__class__', Bar)
              >
              But what surprised me was that this *didn't* work:
              >
              >f = Foo()
              >f.__dict__['__class__'] = Bar
              >f.__class__
              >
              <class '__main__.Foo'>
              >
              Unless I'm confused, it looks like instance.__clas s__ bypasses the usual
              lookup mechanism (instance.__dic t__, then instance.__clas s__.__dict__) for
              some reason.
              >
              >Foo.x = 1 # stored in class __dict__
              >f.x
              1
              >f.__dict__['x'] = 2 # stored in instance __dict__
              >f.x
              2
              >Foo.x
              >
              1
              >
              But __class__ doesn't behave like this. Why?
              >
              Magic attributes like __class__ are looked up on the class rather than
              the instance.

              Fuzzyman
              http://www.voidspace.org.uk/python/articles.shtml
              --
              Steven.

              Comment

              • Facundo Batista

                #8
                Re: Bypassing __setattr__ for changing special attributes

                Ziga Seilnacht wrote:

                >>>object.__set attr__(f, '__class__', Bar)
                >>>f.__class_ _ is Bar
                True
                Interesting, but... why I must do this? And, I must *always* do this?

                With Foo and Bar like the OP coded (just two new style classes, f is
                instance of Foo), see this:
                >>f
                <__main__.Foo object at 0xb7d1280c>
                >>setattr(f, '__class__', Bar)
                >>f
                <__main__.Foo object at 0xb7d1280c>


                Ok, didn't work, try your way:
                >>object.__seta ttr__(f, '__class__', Bar)
                >>f
                <__main__.Bar object at 0xb7d1280c>


                Wow! Ok, but getting back to Foo, with the *former* method:
                >>setattr(f, '__class__', Foo)
                >>f
                <__main__.Foo object at 0xb7d1280c>


                I can't explain this to myself, :(

                Regards,

                --
                .. Facundo
                ..
                Blog: http://www.taniquetil.com.ar/plog/
                PyAr: http://www.python.org/ar/



                Comment

                Working...