Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > hasattr + __getattr__: I think this is Python bug

Reply
Thread Tools

hasattr + __getattr__: I think this is Python bug

 
 
dmitrey
Guest
Posts: n/a
 
      07-20-2010
hi all,
I have a class (FuncDesigner oofun) that has no attribute "size", but
it is overloaded in __getattr__, so if someone invokes
"myObject.size", it is generated (as another oofun) and connected to
myObject as attribute.

So, when I invoke in other code part "hasattr(myObject, 'size')",
instead o returning True/False it goes to __getattr__ and starts
constructor for another one oofun, that wasn't intended behaviour.
Thus "hasattr(myObject, 'size')" always returns True. It prevents me
of some bonuses and new features to be done in FuncDesigner.

>>> 'size' in dir(b)

False
>>> hasattr(b,'size')

True
>>> 'size' in dir(b)

True

Could you fix it?
 
Reply With Quote
 
 
 
 
Chris Rebert
Guest
Posts: n/a
 
      07-20-2010
On Tue, Jul 20, 2010 at 3:10 AM, dmitrey <(E-Mail Removed)> wrote:
> hi all,
> I have a class (FuncDesigner oofun) that has no attribute "size", but
> it is overloaded in __getattr__, so if someone invokes
> "myObject.size", it is generated (as another oofun) and connected to
> myObject as attribute.
>
> So, when I invoke in other code part "hasattr(myObject, 'size')",
> instead o returning True/False it goes to __getattr__ and starts
> constructor for another one oofun, that wasn't intended behaviour.
> Thus "hasattr(myObject, 'size')" always returns True. It prevents me
> of some bonuses and new features to be done in FuncDesigner.
>
>>>> 'size' in dir(b)

> False
>>>> hasattr(b,'size')

> True
>>>> 'size' in dir(b)

> True
>
> Could you fix it?


There's probably some hackery you could do to check whether hasattr()
is in the call stack, and then not dynamically create the attribute in
__getattr__ if that's the case, but that's obviously quite kludgey.

/Slightly/ less hackish: Replace hasattr() in the __builtin__ module
with your own implementation that treats instances of FuncDesigner
specially.

Least ugly suggestion: Just don't use hasattr(); use your `x in
dir(y)` trick instead.

> Subject: [...] I think this is Python bug

Nope, that's just how hasattr() works. See
http://docs.python.org/library/functions.html#hasattr (emphasis mine):
"""
hasattr(object, name)
The arguments are an object and a string. The result is True if
the string is the name of one of the object’s attributes, False if
not. (***This is implemented by calling getattr(object, name)*** and
seeing whether it raises an exception or not.)
"""

I suppose you could argue for the addition of a __hasattr__ special
method, but this seems like a really rare use case to justify adding
such a method (not to mention the language change moratorium is still
currently in effect).

Cheers,
Chris
--
http://blog.rebertia.com
 
Reply With Quote
 
 
 
 
dmitrey
Guest
Posts: n/a
 
      07-20-2010
On Jul 20, 1:37*pm, Chris Rebert <(E-Mail Removed)> wrote:
> On Tue, Jul 20, 2010 at 3:10 AM, dmitrey <(E-Mail Removed)> wrote:
> > hi all,
> > I have a class (FuncDesigner oofun) that has no attribute "size", but
> > it is overloaded in __getattr__, so if someone invokes
> > "myObject.size", it is generated (as another oofun) and connected to
> > myObject as attribute.

>
> > So, when I invoke in other code part "hasattr(myObject, 'size')",
> > instead o returning True/False it goes to __getattr__ and starts
> > constructor for another one oofun, that wasn't intended behaviour.
> > Thus "hasattr(myObject, 'size')" always returns True. It prevents me
> > of some bonuses and new features to be done in FuncDesigner.

>
> >>>> 'size' in dir(b)

> > False
> >>>> hasattr(b,'size')

> > True
> >>>> 'size' in dir(b)

> > True

>
> > Could you fix it?

>
> There's probably some hackery you could do to check whether hasattr()
> is in the call stack, and then not dynamically create the attribute in
> __getattr__ if that's the case, but that's obviously quite kludgey.


It's too unreliable solution, hasattr may or may not appear in stack
wrt different cases

> /Slightly/ less hackish: Replace hasattr() in the __builtin__ module
> with your own implementation that treats instances of FuncDesigner
> specially.


It's too unreliable as well

> Least ugly suggestion: Just don't use hasattr(); use your `x in
> dir(y)` trick instead.


something in dir() consumes O(n) operations for lookup, while hasattr
or getattr() require O(log(n)). It matters for me, because it's inside
deeply nested mathematical computations FuncDesigner is made for.

>
> > Subject: [...] I think this is Python bug

>
> Nope, that's just how hasattr() works. Seehttp://docs.python.org/library/functions.html#hasattr(emphasis mine):
> """
> hasattr(object, name)
> * * The arguments are an object and a string. The result is True if
> the string is the name of one of the objects attributes, False if
> not. (***This is implemented by calling getattr(object, name)*** and
> seeing whether it raises an exception or not.)
> """


Thus I believe this is very ugly implementation. Some code implemented
via "__getattr__" can start to execute arbitrary Python code, that is
certainly not desired behaviour "hasattr" was designed for (to perform
a check only), and it's too hard to reveal the situations, that makes
a potential holes for viruses etc.

Moreover, the implementation via "try getattr(object, name)" slowers
code evaluation, I wonder why it is implemented so.

>
> I suppose you could argue for the addition of a __hasattr__ special
> method, but this seems like a really rare use case to justify adding
> such a method (not to mention the language change moratorium is still
> currently in effect).


I think much more easier solution would be to implement an additional
argument to hasattr, e.g. hasattr(obj, field,
onlyLookupInExistingFields = {True/False}). I think by default it's
better set to True, now it behaves like False.

D.
 
Reply With Quote
 
Jean-Michel Pichavant
Guest
Posts: n/a
 
      07-20-2010
dmitrey wrote:
> hi all,
> I have a class (FuncDesigner oofun) that has no attribute "size", but
> it is overloaded in __getattr__, so if someone invokes
> "myObject.size", it is generated (as another oofun) and connected to
> myObject as attribute.
>
> So, when I invoke in other code part "hasattr(myObject, 'size')",
> instead o returning True/False it goes to __getattr__ and starts
> constructor for another one oofun, that wasn't intended behaviour.
> Thus "hasattr(myObject, 'size')" always returns True. It prevents me
> of some bonuses and new features to be done in FuncDesigner.
>
>
>>>> 'size' in dir(b)
>>>>

> False
>
>>>> hasattr(b,'size')
>>>>

> True
>
>>>> 'size' in dir(b)
>>>>

> True
>
> Could you fix it?
>


Quite simple, when calling b.size, return the computed value but do not
set it as attribute, the value will be computed on each b.size call, and
hasattr w. If you don't want to compute it each time, cause there no
reason for it to change, use a private dummy attribute to record the
value instead of size (__size for instance) and return the value of
__size when getting the value of size.


class Foo(object):
def __init__(self):
self.__size = None

def __getattr__(self, name):
if name == "size":
if self.__size is None:
self.__size = 5 # compute the value
return self.__size
raise AttributeError(name)

b = Foo()
print 'size' in dir(b)
print hasattr(b, 'size')
print 'size' in dir(b)

False
True
False

JM
 
Reply With Quote
 
dmitrey
Guest
Posts: n/a
 
      07-20-2010
On 20 июл, 15:00, Jean-Michel Pichavant <(E-Mail Removed)>
wrote:
> dmitrey wrote:
> > hi all,
> > I have a class (FuncDesigner oofun) that has no attribute "size", but
> > it is overloaded in __getattr__, so if someone invokes
> > "myObject.size", it is generated (as another oofun) and connected to
> > myObject as attribute.

>
> > So, when I invoke in other code part "hasattr(myObject, 'size')",
> > instead o returning True/False it goes to __getattr__ and starts
> > constructor for another one oofun, that wasn't intended behaviour.
> > Thus "hasattr(myObject, 'size')" always returns True. It prevents me
> > of some bonuses and new features to be done in FuncDesigner.

>
> >>>> 'size' in dir(b)

>
> > False

>
> >>>> hasattr(b,'size')

>
> > True

>
> >>>> 'size' in dir(b)

>
> > True

>
> > Could you fix it?

>
> Quite simple, when calling b.size, return the computed value but do not
> set it as attribute, the value will be computed on each b.size call, and
> hasattr w. If you don't want to compute it each time, cause there no
> reason for it to change, use a private dummy attribute to record the
> value instead of size (__size for instance) and return the value of
> __size when getting the value of size.
>
> class Foo(object):
> * * def __init__(self):
> * * * * self.__size = None
>
> * * def __getattr__(self, name):
> * * * * if name == "size":
> * * * * * * if self.__size is None:
> * * * * * * * * self.__size = 5 # compute the value
> * * * * * * return self.__size
> * * * * raise AttributeError(name)
>
> b = Foo()
> print 'size' in dir(b)
> print hasattr(b, 'size')
> print 'size' in dir(b)
>
> False
> True
> False
>
> JM


This doesn't stack with the following issue: sometimes user can write
in code "myObject.size = (some integer value)" and then it will be
involved in future calculations as ordinary fixed value; if user
doesn't supply it, but myObject.size is involved in calculations, then
the oofun is created to behave like similar numpy.array attribute.
 
Reply With Quote
 
dmitrey
Guest
Posts: n/a
 
      07-20-2010
> e.g. one that just looks in the object's dictionary so as to avoid returning true for properties or other such fancy attributes.

So can anyone explain me how to look into object's dict? As I have
wrote, "something in dir(...)" requires O(numOfFields) while I would
like to use o(log(n))

>How about using a property instead of the __getattr__() hook? A property is a computed attribute that (among other things) plays much nicer with hasattr.


Could anyone provide an example of it to be implemented, taking into
account that a user can manually set "myObject.size" to an integer
value?
 
Reply With Quote
 
Neil Cerutti
Guest
Posts: n/a
 
      07-20-2010
On 2010-07-20, dmitrey <(E-Mail Removed)> wrote:
> This doesn't stack with the following issue: sometimes user can
> write in code "myObject.size = (some integer value)" and then
> it will be involved in future calculations as ordinary fixed
> value; if user doesn't supply it, but myObject.size is involved
> in calculations, then the oofun is created to behave like
> similar numpy.array attribute.


Telling them, "Don't do that," is a good solution in Python.

--
Neil Cerutti
 
Reply With Quote
 
dmitrey
Guest
Posts: n/a
 
      07-20-2010
On 20 июл, 18:39, Neil Cerutti <(E-Mail Removed)> wrote:
> On 2010-07-20, dmitrey <(E-Mail Removed)> wrote:
>
> > This doesn't stack with the following issue: sometimes user can
> > write in code "myObject.size = (some integer value)" and then
> > it will be involved in future calculations as ordinary fixed
> > value; if user doesn't supply it, but myObject.size is involved
> > in calculations, then the oofun is created to behave like
> > similar numpy.array attribute.

>
> Telling them, "Don't do that," is a good solution in Python.
>
> --
> Neil Cerutti


But this is already documented feature, and it works as intended, so
moving it into something like "myObject._size" will bring backward
incompatibility and break all FuncDesigner user API and style, where
no underlines are present, it will seem like a hack that it really
is.

Sometimes apriory knowing size value as fixed integer brings some code
speedup, also, if a user supplies the value, a check for computed
value wrt the provided size is performed each time.
 
Reply With Quote
 
Jean-Michel Pichavant
Guest
Posts: n/a
 
      07-20-2010
dmitrey wrote:
> On 20 июл, 15:00, Jean-Michel Pichavant <(E-Mail Removed)>
> wrote:
>
>> dmitrey wrote:
>>
>>> hi all,
>>> I have a class (FuncDesigner oofun) that has no attribute "size", but
>>> it is overloaded in __getattr__, so if someone invokes
>>> "myObject.size", it is generated (as another oofun) and connected to
>>> myObject as attribute.
>>>
>>> So, when I invoke in other code part "hasattr(myObject, 'size')",
>>> instead o returning True/False it goes to __getattr__ and starts
>>> constructor for another one oofun, that wasn't intended behaviour.
>>> Thus "hasattr(myObject, 'size')" always returns True. It prevents me
>>> of some bonuses and new features to be done in FuncDesigner.
>>>
>>>>>> 'size' in dir(b)
>>>>>>
>>> False
>>>
>>>>>> hasattr(b,'size')
>>>>>>
>>> True
>>>
>>>>>> 'size' in dir(b)
>>>>>>
>>> True
>>>
>>> Could you fix it?
>>>

>> Quite simple, when calling b.size, return the computed value but do not
>> set it as attribute, the value will be computed on each b.size call, and
>> hasattr w. If you don't want to compute it each time, cause there no
>> reason for it to change, use a private dummy attribute to record the
>> value instead of size (__size for instance) and return the value of
>> __size when getting the value of size.
>>
>> class Foo(object):
>> def __init__(self):
>> self.__size = None
>>
>> def __getattr__(self, name):
>> if name == "size":
>> if self.__size is None:
>> self.__size = 5 # compute the value
>> return self.__size
>> raise AttributeError(name)
>>
>> b = Foo()
>> print 'size' in dir(b)
>> print hasattr(b, 'size')
>> print 'size' in dir(b)
>>
>> False
>> True
>> False
>>
>> JM
>>

>
> This doesn't stack with the following issue: sometimes user can write
> in code "myObject.size = (some integer value)" and then it will be
> involved in future calculations as ordinary fixed value; if user
> doesn't supply it, but myObject.size is involved in calculations, then
> the oofun is created to behave like similar numpy.array attribute.
>

Here are some solutions in my humble order of preference:
1/ ask the user to always fill the size field
2/ ask the user to never fill the size filed (you can override
__setattr__ to make sure...)
3/ override __setattr__ to set __size instead of size

JM
 
Reply With Quote
 
Robert Kern
Guest
Posts: n/a
 
      07-20-2010
On 7/20/10 6:59 AM, dmitrey wrote:
> On Jul 20, 1:37 pm, Chris Rebert<(E-Mail Removed)> wrote:


>> Least ugly suggestion: Just don't use hasattr(); use your `x in
>> dir(y)` trick instead.

>
> something in dir() consumes O(n) operations for lookup, while hasattr
> or getattr() require O(log(n)). It matters for me, because it's inside
> deeply nested mathematical computations FuncDesigner is made for.


I'm not sure where you are getting log(n) from, but regardless, if you have so
many attributes that the O() matters more than the constant, you have more
problems than this.

--
Robert Kern

"I have come to believe that the whole world is an enigma, a harmless enigma
that is made terrible by our own mad attempt to interpret it as though it had
an underlying truth."
-- Umberto Eco

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
style question - hasattr ian Python 2 04-09-2008 04:41 AM
problems with hasattr() and custom __getattr__ inside urllib2 Gil Tal Python 0 08-24-2005 05:31 PM
Confused about hasattr/getattr/namespaces Brian Roberts Python 2 02-29-2004 07:07 PM
private class members and hasattr Dragos Chirila Python 2 01-23-2004 10:47 AM
Think Off Brand Inks Are Just as Good in your Inkjet Printer - Think Again! John Horner Digital Photography 5 11-09-2003 09:38 PM



Advertisments