getattr() woes

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Thomas Rast

    #1

    getattr() woes

    Hello

    I've found out about a fundamental problem of attribute lookup, the
    hard way.

    asyncore.py uses the following code:

    class dispatcher:
    # ...
    def __getattr__(sel f, attr):
    return getattr(self.so cket, attr)

    Now suppose that I'm asking for some attribute not provided by
    dispatcher: The lookup mechanism will apparently try to find it
    directly and fail, generating an AttributeError; next it will call
    __getattr__ to find the attribute. So far, no problems.

    But I used a property much like this:
    [color=blue][color=green][color=darkred]
    >>> import asyncore
    >>> class Peer(asyncore.d ispatcher):[/color][/color][/color]
    .... def _get_foo(self):
    .... # caused by a bug, several stack levels deeper
    .... raise AttributeError( 'hidden!')
    .... foo = property(_get_f oo)
    ....

    and as the error message suggests, the original AttributeError is
    hidden by the lookup mechanism:
    [color=blue][color=green][color=darkred]
    >>> Peer().foo[/color][/color][/color]
    Traceback (most recent call last):
    File "<stdin>", line 1, in ?
    File "/usr/lib/python2.4/asyncore.py", line 366, in __getattr__
    return getattr(self.so cket, attr)
    AttributeError: 'NoneType' object has no attribute 'foo'

    Is there anything that can be done about this? If there are no better
    solutions, perhaps the documentation for property() could point out
    this pitfall?

    - Thomas

    --
    If you want to reply by mail, substitute my first and last name for
    'foo' and 'bar', respectively, and remove '.invalid'.
  • Aahz

    #2
    Re: getattr() woes

    In article <87hdm5hnet.fsf @thomas.local>,
    Thomas Rast <foo.bar@freesu rf.ch.invalid> wrote:[color=blue]
    >
    >I've found out about a fundamental problem of attribute lookup, the
    >hard way.[/color]

    Maybe.
    [color=blue]
    >asyncore.py uses the following code:
    >
    >class dispatcher:
    > # ...
    > def __getattr__(sel f, attr):
    > return getattr(self.so cket, attr)
    >
    >Now suppose that I'm asking for some attribute not provided by
    >dispatcher: The lookup mechanism will apparently try to find it
    >directly and fail, generating an AttributeError; next it will call
    >__getattr__ to find the attribute. So far, no problems.
    >
    >But I used a property much like this:
    >[color=green][color=darkred]
    >>>> import asyncore
    >>>> class Peer(asyncore.d ispatcher):[/color][/color]
    >... def _get_foo(self):
    >... # caused by a bug, several stack levels deeper
    >... raise AttributeError( 'hidden!')
    >... foo = property(_get_f oo)
    >...[/color]

    You're not supposed to use properties with classic classes.
    --
    Aahz (aahz@pythoncra ft.com) <*> http://www.pythoncraft.com/

    "19. A language that doesn't affect the way you think about programming,
    is not worth knowing." --Alan Perlis

    Comment

    • David M. Cooke

      #3
      Re: getattr() woes

      aahz@pythoncraf t.com (Aahz) writes:
      [color=blue]
      > In article <87hdm5hnet.fsf @thomas.local>,
      > Thomas Rast <foo.bar@freesu rf.ch.invalid> wrote:[color=green]
      >>
      >>class dispatcher:
      >> # ...
      >> def __getattr__(sel f, attr):
      >> return getattr(self.so cket, attr)
      >>[color=darkred]
      >>>>> import asyncore
      >>>>> class Peer(asyncore.d ispatcher):[/color]
      >>... def _get_foo(self):
      >>... # caused by a bug, several stack levels deeper
      >>... raise AttributeError( 'hidden!')
      >>... foo = property(_get_f oo)
      >>...[/color]
      >
      > You're not supposed to use properties with classic classes.[/color]

      Even if dispatcher was a new-style class, you still get the same
      behaviour (or misbehaviour) -- Peer().foo still raises AttributeError
      with the wrong message.

      A simple workaround is to put a try ... except AttributeError block in
      his _get_foo(), which would re-raise with a different error that
      wouldn't be caught by getattr. You could even write a property
      replacement for that:
      [color=blue][color=green][color=darkred]
      >>> class HiddenAttribute Error(Exception ):[/color][/color][/color]
      .... pass[color=blue][color=green][color=darkred]
      >>> def robustprop(fget ):[/color][/color][/color]
      .... def wrapped_fget(se lf):
      .... try:
      .... return fget(self)
      .... except AttributeError, e:
      .... raise HiddenAttribute Error(*e.args)
      .... return property(fget=w rapped_fget)

      Ideally, I think the better way is if getattr, when raising
      AttributeError, somehow reused the old traceback (which would point
      out the original problem). I don't know how to do that, though.

      --
      |>|\/|<
      /--------------------------------------------------------------------------\
      |David M. Cooke
      |cookedm(at)phy sics(dot)mcmast er(dot)ca

      Comment

      • Nicolas Fleury

        #4
        Re: getattr() woes

        David M. Cooke wrote:[color=blue]
        > Ideally, I think the better way is if getattr, when raising
        > AttributeError, somehow reused the old traceback (which would point
        > out the original problem). I don't know how to do that, though.[/color]

        Maybe a solution could be to put the attribute name in the
        AttributeError exception object, and use it in getattr; if the name
        doesn't match, the exception is re-raised. It's still not flawless, but
        would reduce risk of errors.

        Nicolas

        Comment

        • Kamilche

          #5
          Re: getattr() woes

          Thomas Rast wrote:[color=blue]
          > I've found out about a fundamental problem of attribute lookup, the
          > hard way... Is there anything that can be done about this?[/color]

          It seems to me that the main problem is you're raising an AttributeError
          when an attribute is private. AttributeError is only raised when an
          attribute is not found. If you found it, but it's private, that's a
          different problem. Try raising a custom exception instead of an
          AttributeError, if you can.



          Comment

          Working...