On 2010-08-23, at 3:47 PM, Raymond Hettinger wrote:

> 
> On Aug 23, 2010, at 7:22 AM, Yury Selivanov wrote:
> 
>> I know the issue has been discussed several times already, however I 
>> couldn't find any reasonable explanation of its strange behaviour.  The main 
>> problem with 'hasattr' function is that is swallows all exceptions derived 
>> from Exception class.  It's a good thing that it doesn't do that with 
>> BaseException as it was fixed not a long time ago, but it's definitely not 
>> enough.
>> 
>> First of all, this behaviour of 'hasattr' contradicts with the very core 
>> principle of python: "Errors should never pass silently."  And since 
>> 'hasattr' function is in builtins module and is a widely used function it 
>> impacts the whole language.
>> 
>> Secondly, take a look at the following:
>> 
>>>>> class Test:
>>   ...     @property
>>   ...     def attr(self):
>>   ...         self['foo']
>>   ... 
>>>>> hasattr(Test(), 'attr')
>>   False
>> 
>> There can be any exception instead of KeyError in the above snippet of code, 
>> but this small example shows how 'hasattr': misleadingly breaks the code 
>> logic (1) and masks bug (2).  And that's the simplest possible example, 
>> there are much more in real life.
>> 
>> While (1) is maybe acceptable for someone, there is no excuse for the (2).  
>> Moreover, current 'hasattr' behaviour tremendously complicates use of 
>> '__getattribute__' magic.  And forget about importlib magic with 
>> LazyImports, one 'hasattr' ruins everything by catching ImportError.
>> 
>> 
>> To conclude:
>> 
>> 1) I propose to change 'hasattr' behaviour in Python 3, making it to swallow 
>> only AttributeError exceptions (exactly like 'getattr').  Probably, Python 
>> 3.2 release is our last chance.
>> 
>> 2) If you afraid that this new behaviour will break too much python 2 code 
>> converted with 2to3, we can introduce another 'hasattr' function defined in 
>> 2to3 module itself, and make it imported automatically in all files passed 
>> through 2to3 transformation pipeline.  This new function will mimic 
>> 'hasattr' behaviour from python 2 and converted code should work as expected.
> 
> 
> Thanks for the nice analysis and good example.
> 
> I disagree with the solution though.  If we want to see the exceptions 
> associated 
> with actually getting an attribute, then using getattr() instead is a 
> perfectly 
> reasonable solution that people can already use without a language change.
> 
> But hasattr() has a far different set of use cases, so we should explore
> an alternate solution to the problem.  The usual reason that people use
> hasattr() instead of getattr() is that they want to check for the presence of
> of a method/attribute without actually running it, binding it, or triggering
> any other behavior.
> 
> As your example shows, property() defeats this intent by actually executing
> the code.   A better behavior would not run the code at all.  It would check
> the dictionaries along the MRO but not execute any descriptors associated
> with a given key.
> 
> IMO, this is a much better solution, more in line with known use cases
> for hasattr().   If the proposed change when through, it would fail to
> address the common use case and cause people to start writing their
> own versions of hasattr() that just scan but do not run code.

This is impossible to implement because of '__getattribute__' and '__getattr__' 
methods.  There is no way of detecting the presence of an attribute but trying 
to get it through 'getattr'.  Partial solution like getting information about 
property presence through __dict__ and call __getattribute__/__getattr__ if 
they are defined wouldn't work either.

So, your solution would make 'hasattr' even more incompatible.

-
Yury Selivanov
_______________________________________________
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com

Reply via email to