Re: NameError vs AttributeError

2012-08-01 Thread Ethan Furman

Terry Reedy wrote:

On 7/31/2012 4:49 PM, Chris Kaynor wrote:

On Tue, Jul 31, 2012 at 1:21 PM, Terry Reedy wrote:

Another example: KeyError and IndexError are both subscript errors,
but there is no SubscriptError superclass, even though both work
thru the same mechanism -- __getitem__.  The reason is that there is
no need for one. In 'x[y]', x is usually intented to be either a
sequence or mapping, but not possibly both. In the rare cases when
one wants to catch both errors, one can easily enough. To continue
the example above, popping an empty list and empty set produce
IndexError and KeyError respectively:

   try:
 while True:
   process(pop())
   except (KeyError, IndexError):
 pass  # empty collection means we are done


There is a base type for KeyError and IndexError: LookupError.

http://docs.python.org/library/exceptions.html#exception-hierarchy


Oh, so there is. Added in 1.5 strictly as a never-directly-raised base 
class for the above pair, now also directly raised in codecs.lookup. I 
have not decided if I want to replace the tuple in the code in my book.


I think I'd stick with the tuple -- LookupError could just as easily 
encompass NameError and AttributeError.

--
http://mail.python.org/mailman/listinfo/python-list


Re: NameError vs AttributeError

2012-08-01 Thread Terry Reedy

On 8/1/2012 11:53 AM, Ethan Furman wrote:

Terry Reedy wrote:

On 7/31/2012 4:49 PM, Chris Kaynor wrote:

On Tue, Jul 31, 2012 at 1:21 PM, Terry Reedy wrote:



one wants to catch both errors, one can easily enough. To continue
the example above, popping an empty list and empty set produce
IndexError and KeyError respectively:

   try:
 while True:
   process(pop())
   except (KeyError, IndexError):
 pass  # empty collection means we are done


There is a base type for KeyError and IndexError: LookupError.

http://docs.python.org/library/exceptions.html#exception-hierarchy


Oh, so there is. Added in 1.5 strictly as a never-directly-raised base
class for the above pair, now also directly raised in codecs.lookup. I
have not decided if I want to replace the tuple in the code in my book.


I think I'd stick with the tuple -- LookupError could just as easily
encompass NameError and AttributeError.


Thank you. Having to remember exactly which lookup error is encompassed 
by LookupError illustrates my point about the cost of adding entities 
without necessity. It also illustrates the importance of carefull 
naming. SubscriptError might have been better.


--
Terry Jan Reedy



--
http://mail.python.org/mailman/listinfo/python-list


NameError vs AttributeError

2012-07-31 Thread Ulrich Eckhardt

Hi!

Using Python 2.7, I stumbled across the fact that 'self.xy' raises an 
AttributeError if self doesn't have an 'xy' as attribute, but 'xy' will 
instead raise a NameError. To some extent, these two are very similar, 
namely that the name 'xy' couldn't be resolved in a certain context, but 
they don't have a common baseclass.


I guess one of the reasons is behind the way that Python handles 
variable lookup, the plain 'xy' will find local and global names while 
'self.xy' will only look into onself. However, this vague idea is far 
from enough to explain it to someone else.


Can someone help me out?

Uli
--
http://mail.python.org/mailman/listinfo/python-list


Re: NameError vs AttributeError

2012-07-31 Thread Terry Reedy

On 7/31/2012 6:36 AM, Ulrich Eckhardt wrote:

Hi!

Using Python 2.7, I stumbled across the fact that 'self.xy' raises an
AttributeError if self doesn't have an 'xy' as attribute, but 'xy' will
instead raise a NameError. To some extent, these two are very similar,
namely that the name 'xy' couldn't be resolved in a certain context, but
they don't have a common baseclass.


You have observed a true fact. The two errors both involve 
non-reconition of identifiers. In most cases, the identifiers are 
looked-up in a dict.



I guess one of the reasons is behind the way that Python handles
variable lookup, the plain 'xy' will find local and global names while
'self.xy' will only look into onself. However, this vague idea is far
from enough to explain it to someone else.

Can someone help me out?


1. Why two separate exceptions:

a) operational: two separate exceptions are possible.

Name lookup and attribute lookup goes thru separate machinery. Name 
lookup may go thru local, nonlocal, global (modular) and builtin 
namespaces. Attribute lookup goes thru instance, class, and superclasses 
to object. Name lookup is fixed except for nonlocal and global 
declarations local assignments. Attribute lookup can be over-riden with 
special methods (and special method lookup skips the instance).


b) practical: two separate exceptions are desirable.

One catches an exception to do something in the except clause. Name and 
attribute errors often have different causes and different associated 
actions.


def empty_and_process(poppable, process):
  try:
pop = popable.pop
  except AttributeError:
raise AttributeError(Can only empty_and_process objects with .pop 
method)


Whoops, programming typo raises NameError. It should *not* be caught, 
rather bug should be fixed.


Later usage error gets AttributeError, possibly documented. User decides 
whether it represents a bug to be fixed (the default) or a control 
signal to be caught and processed.


If one really does want the same action for the different mistakes, 
except (NameError, AttributeError): is easy enough to write.


2. Why no special base exception (NameAttrError ?).

Python exceptions started as strings with NO hierarchy. The current 
class system is still relatively flat. Flat is better than nested 
because nesting introduces a new entities and new entities should not be 
introduced without sufficient purpose and each one makes the whole 
harder to learn and remember. I suspect that if you grepped a large 
Python code corpus for this particular pair in except statements you 
would find it rare.


---
Another example: KeyError and IndexError are both subscript errors, but 
there is no SubscriptError superclass, even though both work thru the 
same mechanism -- __getitem__.  The reason is that there is no need for 
one. In 'x[y]', x is usually intented to be either a sequence or 
mapping, but not possibly both. In the rare cases when one wants to 
catch both errors, one can easily enough. To continue the example above, 
popping an empty list and empty set produce IndexError and KeyError 
respectively:


  try:
while True:
  process(pop())
  except (KeyError, IndexError):
pass  # empty collection means we are done

--
Terry Jan Reedy



--
http://mail.python.org/mailman/listinfo/python-list


Re: NameError vs AttributeError

2012-07-31 Thread Chris Kaynor
On Tue, Jul 31, 2012 at 1:21 PM, Terry Reedy tjre...@udel.edu wrote:

 Another example: KeyError and IndexError are both subscript errors, but
 there is no SubscriptError superclass, even though both work thru the same
 mechanism -- __getitem__.  The reason is that there is no need for one. In
 'x[y]', x is usually intented to be either a sequence or mapping, but not
 possibly both. In the rare cases when one wants to catch both errors, one
 can easily enough. To continue the example above, popping an empty list and
 empty set produce IndexError and KeyError respectively:


   try:
 while True:
   process(pop())
   except (KeyError, IndexError):
 pass  # empty collection means we are done


There is a base type for KeyError and IndexError: LookupError.

http://docs.python.org/library/exceptions.html#exception-hierarchy




 --
 Terry Jan Reedy



 --
 http://mail.python.org/**mailman/listinfo/python-listhttp://mail.python.org/mailman/listinfo/python-list

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: NameError vs AttributeError

2012-07-31 Thread Terry Reedy

On 7/31/2012 4:49 PM, Chris Kaynor wrote:

On Tue, Jul 31, 2012 at 1:21 PM, Terry Reedy tjre...@udel.edu
mailto:tjre...@udel.edu wrote:

Another example: KeyError and IndexError are both subscript errors,
but there is no SubscriptError superclass, even though both work
thru the same mechanism -- __getitem__.  The reason is that there is
no need for one. In 'x[y]', x is usually intented to be either a
sequence or mapping, but not possibly both. In the rare cases when
one wants to catch both errors, one can easily enough. To continue
the example above, popping an empty list and empty set produce
IndexError and KeyError respectively:

   try:
 while True:
   process(pop())
   except (KeyError, IndexError):
 pass  # empty collection means we are done

There is a base type for KeyError and IndexError: LookupError.

http://docs.python.org/library/exceptions.html#exception-hierarchy


Oh, so there is. Added in 1.5 strictly as a never-directly-raised base 
class for the above pair, now also directly raised in codecs.lookup. I 
have not decided if I want to replace the tuple in the code in my book.


--
Terry Jan Reedy



--
http://mail.python.org/mailman/listinfo/python-list