Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Exceptions, assigning a tuple

0 views
Skip to first unread message

Derek Fountain

unread,
Nov 21, 2003, 2:03:44 AM11/21/03
to
This came up in another thread, but I thought it was worth asking to the
group in a thread of its own.

What I don't understand is the assignment of a tuple in the except clause.
The O'Reilly Nutshell book says "The optional target is an identifier that
names a variable that Python binds to the exception object just before the
exception handler executes". This doesn't make sense in this case:

except IOError, (errno, strerror):

The target is a tuple of 2 variable names so how can it bind "the exception
object" to them? The documentation for try/except says that "the
exception's parameter is assigned to the target". So what, exactly, is an
"exception's parameter"?

Erik Max Francis

unread,
Nov 21, 2003, 2:09:50 AM11/21/03
to
Derek Fountain wrote:

> What I don't understand is the assignment of a tuple in the except
> clause.
> The O'Reilly Nutshell book says "The optional target is an identifier
> that
> names a variable that Python binds to the exception object just before
> the
> exception handler executes". This doesn't make sense in this case:
>
> except IOError, (errno, strerror):
>
> The target is a tuple of 2 variable names so how can it bind "the
> exception
> object" to them? The documentation for try/except says that "the
> exception's parameter is assigned to the target". So what, exactly, is
> an
> "exception's parameter"?

This is just using tuple unpacking in assignment:

>>> tup = 1, 2, 3
>>> x, y, z = tup
>>> x
1
>>> y
2
>>> z
3

This syntax can be used anywhere an lvalue is allowed, which might
include the "variable" of a for statement:

>>> for x, y in [(1, 2), (3, 4), (5, 6)]:
... print x, y
...
1 2
3 4
5 6

and the "variable" in a try/except clause is just another example of
this. The "exception's parameter" is a 2-tuple, consisting of the errno
and the strerror.

--
Erik Max Francis && m...@alcyone.com && http://www.alcyone.com/max/
__ San Jose, CA, USA && 37 20 N 121 53 W && &tSftDotIotE
/ \
\__/ Yes I'm / Learning from falling down / Heavily
-- Lamya

Derek Fountain

unread,
Nov 21, 2003, 2:18:49 AM11/21/03
to
>> except IOError, (errno, strerror):

> This is just using tuple unpacking in assignment:
>
>>>> tup = 1, 2, 3
>>>> x, y, z = tup
>>>> x
> 1
>>>> y
> 2
>>>> z
> 3

OK, that makes a lot of sense. However, the thing being unpacked here isn't
a tuple - it's an object of type IOError. How does an object know how to
unpack itself when used in an assignment like this? More specifically, how
does the IOError object know to return its errno and strerror values when
it gets assigned to a 2 value tuple?

Erik Max Francis

unread,
Nov 21, 2003, 2:25:33 AM11/21/03
to
Derek Fountain wrote:

> OK, that makes a lot of sense. However, the thing being unpacked here
> isn't
> a tuple - it's an object of type IOError. How does an object know how
> to
> unpack itself when used in an assignment like this? More specifically,
> how
> does the IOError object know to return its errno and strerror values
> when
> it gets assigned to a 2 value tuple?

Because the Exception class, which IOError is derived from, works that
way:

>>> e = Exception(1, 2, 3)
>>> tuple(e)
(1, 2, 3)
>>> x, y, z = e


>>> x
1
>>> y
2
>>> z
3

The "exception parameter" is an exception object, which knows how to
behave like a tuple.

Derek Fountain

unread,
Nov 21, 2003, 2:41:30 AM11/21/03
to
> The "exception parameter" is an exception object, which knows how to
> behave like a tuple.

OK, and what gives it that ability? I tried tuple(f), where f was a file
object. It gave me the contents of the file! I tried it again on an
instance of one of my own objects and got a "TypeError: iteration over
non-sequence" exception.

It must be possible to give a class the ability to present itself as a
tuple. How is that done?

Erik Max Francis

unread,
Nov 21, 2003, 2:56:49 AM11/21/03
to
Derek Fountain wrote:

> OK, and what gives it that ability? I tried tuple(f), where f was a
> file
> object. It gave me the contents of the file! I tried it again on an
> instance of one of my own objects and got a "TypeError: iteration over
> non-sequence" exception.
>
> It must be possible to give a class the ability to present itself as a
> tuple. How is that done?

The tuple function can work with instances which support an iterating
interface. (This is why you were seeing this behavior with a file
object; iterating over a file object gives you the lines in sequence.)

>>> class C:
... def __init__(self, x):
... self.x = x
... def __getitem__(self, i):
... if i < self.x:
... return i**2
... else:
... raise IndexError
...
>>> c = C(10)
>>> tuple(c)
(0, 1, 4, 9, 16, 25, 36, 49, 64, 81)

Derek Fountain

unread,
Nov 21, 2003, 3:19:18 AM11/21/03
to
> The tuple function can work with instances which support an iterating
> interface.

And that's the final piece of the puzzle! I can now claim to understand it.
Many thanks.

Erik Max Francis

unread,
Nov 21, 2003, 4:01:54 AM11/21/03
to
Derek Fountain wrote:

> And that's the final piece of the puzzle! I can now claim to
> understand it.
> Many thanks.

Sure thing. By the way, that little explanation is a hint at one of the
key insights to Python. A lot of features in Python work like that --
you don't have to provide dedicated support for a certain builtin
function to do its work (e.g., using the `tuple' function to make a
tuple out of an arbitrary object), you only need to make the object
conform to the relevant interface. In this case, it was the iteration
interface -- tuple will work with any object that can be iterated over.
So exactly the same property that allows you to write:

for x in myObject:
...

is precisely the same one that makes

tuple(myObject)

meaningful and do what you'd expect. For instance, to get a file-like
object, you don't actually need a literal file object (created with
`file'), you just need something that has the relevant methods (read,
readlines, write, writelines, flush, close, or a subset). Often these
sorts of interfaces are orthogonal, so that's why you saw that native
file objects actually can behave as iteratable objects as well -- all
they need to do is support read/write/flush/close and __getitem__ in the
expected way (start from 0, raise IndexError when you're done).

--
Erik Max Francis && m...@alcyone.com && http://www.alcyone.com/max/
__ San Jose, CA, USA && 37 20 N 121 53 W && &tSftDotIotE
/ \

\__/ You're wasting time / Asking what if / You linger on too long
-- Chante Moore

Gonçalo Rodrigues

unread,
Nov 21, 2003, 7:08:10 AM11/21/03
to
On Thu, 20 Nov 2003 23:56:49 -0800, Erik Max Francis <m...@alcyone.com>
wrote:

>Derek Fountain wrote:
>
>> OK, and what gives it that ability? I tried tuple(f), where f was a
>> file
>> object. It gave me the contents of the file! I tried it again on an
>> instance of one of my own objects and got a "TypeError: iteration over
>> non-sequence" exception.
>>
>> It must be possible to give a class the ability to present itself as a
>> tuple. How is that done?
>
>The tuple function can work with instances which support an iterating
>interface. (This is why you were seeing this behavior with a file
>object; iterating over a file object gives you the lines in sequence.)
>
>>>> class C:
>... def __init__(self, x):
>... self.x = x
>... def __getitem__(self, i):
>... if i < self.x:
>... return i**2
>... else:
>... raise IndexError
>...

Hmm. More generally you have to implement __iter__ for a class to be
iterable, be in for loops => can be list-ified, tuple-ified,
etc.-ified.

>>> class C(object):


... def __init__(self, x):
... self.x = x

... def __iter__(self):
... return iter(range(self.x))
...
>>> c = C(9)
>>> for elem in c:
... print elem
...
0


1
2
3
4
5
6

7
8
>>> tuple(c)
(0, 1, 2, 3, 4, 5, 6, 7, 8)
>>> list(c)
[0, 1, 2, 3, 4, 5, 6, 7, 8]
>>> 2 in c
True
>>> "2" in c
False
>>>

With my best regards,
G. Rodrigues

Erik Max Francis

unread,
Nov 21, 2003, 4:55:55 PM11/21/03
to
"Gonçalo Rodrigues" wrote:

> Hmm. More generally you have to implement __iter__ for a class to be
> iterable, be in for loops => can be list-ified, tuple-ified,
> etc.-ified.

Defining an explicit __iter__ method is another way, and is particularly
useful when you're dealing with a class whose iteration can be
encapsulated easily in a separate iterator object that you can return
(and you're running Python 2.2 or up). That isn't always the case.

--
Erik Max Francis && m...@alcyone.com && http://www.alcyone.com/max/
__ San Jose, CA, USA && 37 20 N 121 53 W && &tSftDotIotE
/ \

\__/ Golf is a good walk spoiled.
-- Mark Twain

Mel Wilson

unread,
Nov 21, 2003, 4:58:52 PM11/21/03
to
In article <3FBDBA3E...@alcyone.com>,

Erik Max Francis <m...@alcyone.com> wrote:
>Derek Fountain wrote:
>
>> What I don't understand is the assignment of a tuple in the except
>> clause.
>> [ ... ]

>This is just using tuple unpacking in assignment:
>
>>>> tup = 1, 2, 3
>>>> x, y, z = tup
>>>> x
>1
>>>> y
>2
>>>> z
>3
>
>This syntax can be used anywhere an lvalue is allowed, which might
>include the "variable" of a for statement:
> [ ... ]

>and the "variable" in a try/except clause is just another example of
>this. [ ... ]

The use of tuple unpacking that surprised me most is in
function arguments:


Python 2.3 (#46, Jul 29 2003, 18:54:32) [MSC v.1200 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> def f ( (a,b) ):
... print a, b
...
>>> x = (1,2)
>>> f(x)
1 2
>>>


It almost looks like Prolog unification (but isn't
really.)

Regards. Mel.

Georgy Pruss

unread,
Nov 23, 2003, 6:05:12 PM11/23/03
to

"Mel Wilson" <mwi...@the-wire.com> wrote in message news:cqov/ks/Kjxa...@the-wire.com...

|
| The use of tuple unpacking that surprised me most is in
| function arguments:
|
|
| Python 2.3 (#46, Jul 29 2003, 18:54:32) [MSC v.1200 32 bit (Intel)] on win32
| Type "help", "copyright", "credits" or "license" for more information.
| >>> def f ( (a,b) ):
| ... print a, b
| ...
| >>> x = (1,2)
| >>> f(x)
| 1 2
| >>>
|
| It almost looks like Prolog unification (but isn't
| really.)
|
| Regards. Mel.

That's a trick! Is it used? Does anybody use assignments like this:
(a,((b,(c,)),d,e)) = (1,((2,(3+4,)),5,6))

--
Georgy Pruss
E^mail: 'ZDAwMTEyMHQwMzMwQGhvdG1haWwuY29t\n'.decode('base64')

Emile van Sebille

unread,
Nov 29, 2003, 2:35:35 PM11/29/03
to
Georgy Pruss:
>
> Mel Wilson:

> | The use of tuple unpacking that surprised me most is in
> | function arguments:
[snip]

>
> That's a trick! Is it used? Does anybody use assignments like this:
> (a,((b,(c,)),d,e)) = (1,((2,(3+4,)),5,6))
>

A quick scan of the 2.3 standard library shows that it is used, but
only nestred to one level:

* bdb.py(144): def user_exception(self, frame, (exc_type, exc_value,
exc_traceback)):
* binhex.py(181): def __init__(self, (name, finfo, dlen, rlen),
ofp):
* cgitb.py(168): def text((etype, evalue, etb), context=5):
* cgitb.py(82): def html((etype, evalue, etb), context=5):
* formatter.py(233): def push_font(self, (size, i, b, tt)):
* imputil.py(278): def _process_result(self, (ispkg, code, values),
fqname):
* inspect.py(507): def tokeneater(self, type, token, (srow, scol),
(erow, ecol), line):
* modulefinder.py(258): def load_module(self, fqname, fp, pathname,
(suffix, mode, type)):
* pdb.py(134): def user_exception(self, frame, (exc_type, exc_value,
exc_traceback)):
* pydoc.py(197): def __init__(self, filename, (exc, value, tb)):
* threading.py(126): def _acquire_restore(self, (count, owner)):
* tokenize.py(135): def printtoken(type, token, (srow, scol), (erow,
ecol), line): # for testing

--

Emile van Sebille
em...@fenx.com

0 new messages