f---ing typechecking

S

Szabolcs Nagy

Sergey said:
Python 2.5 (r25:51908, Sep 19 2006, 09:52:17) [MSC v.1310 32 bit (Intel)] on
win32
Type "help", "copyright", "credits" or "license" for more information.
Traceback (most recent call last):
File said:
Traceback (most recent call last):

Its ugly and boring.

what?
for me it works fine:
(1,)+tuple([1]) (1, 1)
[1]+list((1,))
[1, 1]

also
[1, 1]
 
J

James Stroud

Sergey said:
Python 2.5 (r25:51908, Sep 19 2006, 09:52:17) [MSC v.1310 32 bit (Intel)] on
win32
Type "help", "copyright", "credits" or "license" for more information.

Traceback (most recent call last):

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can only concatenate list (not "tuple") to list


Its ugly and boring.

Agreed. This would be similar to:

py> 1 + 1.0

Traceback: can only add int to int. Etc.

But then again, the unimaginative defense would be that it wouldn't be
python if you could catentate a list and a tuple.

James
 
F

Farshid Lashkari

Szabolcs said:

Are list.extend() and list concatenation supposed to behave differently?
I always thought concatenation was just shorthand for calling extend().

However the following seems to work:
>>> L = [1]
>>> L += (2,)
>>> L
[1, 2]

It seems like the '+' operator for lists should accept any iterable for
the right side argument to be consistent with extend() and the '+='
operator.

-Farshid
 
S

Sergey Dorofeev


Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can only concatenate list (not "tuple") to list


Its ugly and boring.

Agreed. This would be similar to:

py> 1 + 1.0

Traceback: can only add int to int. Etc.

But then again, the unimaginative defense would be that it wouldn't be
python if you could catentate a list and a tuple.

Maybe, but I don't think that it is best side of the languague.
If we want constant objects like tuple why not to specify it explicitly?
If we want lists as dict keys, why not to use copy-on-write?
 
S

skip

Concatenating tuples and lists seems logical if you think of tuples as
sequences. If you think of them more like Pascal records or C structs
instead (I believe that's Guido's perspective on tuples) then it makes no
sense at all.

Skip
 
J

James Stroud

Concatenating tuples and lists seems logical if you think of tuples as
sequences. If you think of them more like Pascal records or C structs
instead (I believe that's Guido's perspective on tuples) then it makes no
sense at all.

Skip

Then iterating over them makes no sense?

James
 
S

skip

James> Then iterating over them makes no sense?

I agree that tuples are a bit schizophrenic. They really are sequences from
an implementation standpoint, but from a logical standpoint it's maybe best
not to think of them that way.

That said, this:

for x in (1,2,3):
pass

is a skosh faster (perhaps an immeasurably small skosh) than this:

for x in [1,2,3]:
pass

so people will probably continue to use tuples instead of lists in these
sorts of situations.

For an example of the struct-ness of a tuple consider the output of os.stat:
>>> import os
>>> s = os.stat("/etc/hosts")
>>> s (33188, 34020475L, 234881029L, 1, 0, 0, 214L, 1170562950, 1124700602, 1142602578)
>>> s.st_mtime 1124700602.0
>>> s[0] 33188
>>> type(s)
<type 'posix.stat_result'>

It's effectively a tuple with field names. I don't know when the switch
occurred (it's in 2.2, as far back as my built interpreter versions
currently go), but back in the day os.stat used to return a plain old tuple.

I have no idea if the schizophrenic personality of tuples will improve with
drugs^H^H^H^H^H Python 3, but I wouldn't be at all surprised if it did.

Skip
 
S

Steven D'Aprano

But then again, the unimaginative defense would be that it wouldn't be
python if you could catentate a list and a tuple.

Since lists and tuples are completely different objects with completely
different usages, what should concatenating a list and a tuple give?
Should it depend on the order you pass them?

1.0 + 1 == 1 + 1.0 for very good reasons: we consider (for pragmatic
reasons to do with loss of significant digits) that floats coerce ints
into floats rather than the other way around. But what should lists and
tuples do?

From the Zen of Python:
"In the face of ambiguity, refuse the temptation to guess."
 
J

James Stroud

Steven said:
Since lists and tuples are completely different objects with completely
different usages, what should concatenating a list and a tuple give?
Should it depend on the order you pass them?

Is that a guess or just common sense?
1.0 + 1 == 1 + 1.0 for very good reasons: we consider (for pragmatic
reasons to do with loss of significant digits) that floats coerce ints
into floats rather than the other way around. But what should lists and
tuples do?

From the Zen of Python:
"In the face of ambiguity, refuse the temptation to guess."

Do you guess with __add__ and __radd__?

James
 
J

James Stroud

James> Then iterating over them makes no sense?

I agree that tuples are a bit schizophrenic. They really are sequences from
an implementation standpoint, but from a logical standpoint it's maybe best
not to think of them that way.

That said, this:

for x in (1,2,3):
pass

is a skosh faster (perhaps an immeasurably small skosh) than this:

for x in [1,2,3]:
pass

so people will probably continue to use tuples instead of lists in these
sorts of situations.

For an example of the struct-ness of a tuple consider the output of os.stat:
import os
s = os.stat("/etc/hosts")
s (33188, 34020475L, 234881029L, 1, 0, 0, 214L, 1170562950, 1124700602, 1142602578)
s.st_mtime 1124700602.0
s[0] 33188
type(s)
<type 'posix.stat_result'>

It's effectively a tuple with field names. I don't know when the switch
occurred (it's in 2.2, as far back as my built interpreter versions
currently go), but back in the day os.stat used to return a plain old tuple.

I have no idea if the schizophrenic personality of tuples will improve with
drugs^H^H^H^H^H Python 3, but I wouldn't be at all surprised if it did.

Skip

The arguments for how tuples behave are all very compelling and indeed I
keep them in mind when I code--careful not to confuse their uses. The
problem is that, to the uninitiated, they are redundant and are often
used interchangably. Also, it is very easy for the uninitiated to create
highly functional code in python, and so we get many hybrid uses and
confusion. I increasingly come to the decision to avoid tuples
altogether because, eventually, you end up turning them into lists
anyway and so they begin to represent extra overhead--although its
always fun to try to identify cases when they might provide some value.

James
 
S

Steven D'Aprano

Is that a guess or just common sense?

Sorry, is *what* a guess?

Conceptually, ints are a subset of floats (they certainly are in pure
mathematics). Automatic coercions from ints to floats makes sense;
automatic coercions the other way rarely do -- should you round up or
round down or truncate? What is right in one application is not right for
another.

Lists and tuples, on the other hand, are conceptually two distinct data
types. Adding a list to a tuple is no more sensible than adding a list to
a string -- just because they're both sequences doesn't mean adding them
together is meaningful.

Do you guess with __add__ and __radd__?

No. If there is an obviously correct behaviour for addition (like with
ints and floats) then I coerce the objects appropriately. If there is no
obviously correct behaviour, I refuse to guess.

The user's expected behaviour for [1] + (1,) might be to return a list, or
it might be to return a tuple. Since there is no obviously correct
behaviour, the right thing to do is to refuse to guess.
 
J

James Stroud

Steven said:
Sorry, is *what* a guess?

That it should depend on order.
Conceptually, ints are a subset of floats (they certainly are in pure
mathematics). Automatic coercions from ints to floats makes sense;
automatic coercions the other way rarely do -- should you round up or
round down or truncate? What is right in one application is not right for
another.
>
Lists and tuples, on the other hand, are conceptually two distinct data
types. Adding a list to a tuple is no more sensible than adding a list to
a string -- just because they're both sequences doesn't mean adding them
together is meaningful.
Do you guess with __add__ and __radd__?

No. If there is an obviously correct behaviour for addition (like with
ints and floats) then I coerce the objects appropriately. If there is no
obviously correct behaviour, I refuse to guess.

The user's expected behaviour for [1] + (1,) might be to return a list, or
it might be to return a tuple. Since there is no obviously correct
behaviour, the right thing to do is to refuse to guess.

I guess we differ on what is obvious. This seems obvious to me:

[1] + (1,) => [1, 1]
(1,) + [1] => (1, 1)

simply becuase the operand on the left should take precendence because
its "__add__" is called and its "__add__" returns a list. In essence, as
we know the obviously correct behavior for __add__ and __radd__, then it
would be the obviously correct behavior that the above would follow.

I would venture to guess that most people would intuitively consider the
above behavior correct, simply because the information content
difference between a list versus a tuple is non-existent (outside of the
information that one is a list and the other a tuple). Why would their
types dictate coercion? With ints and floats, as you point out, the
reasons that type dictates coercion are obvious and mathematical. Thus,
for tuples and lists, it wouldn't make sense to consider one type taking
precendence over the other, so we fall back to position, which seems to
be the common sense approach.

James
 
S

Steven D'Aprano

The user's expected behaviour for [1] + (1,) might be to return a list, or
it might be to return a tuple. Since there is no obviously correct
behaviour, the right thing to do is to refuse to guess.

I guess we differ on what is obvious. This seems obvious to me:

[1] + (1,) => [1, 1]
(1,) + [1] => (1, 1)

simply becuase the operand on the left should take precendence because
its "__add__" is called and its "__add__" returns a list.

But that's data dependent. When you call

[1] + MyTuple(1)

your MyTuple.__radd__ will be called first, not the list's __add__.


In essence, as
we know the obviously correct behavior for __add__ and __radd__, then it
would be the obviously correct behavior that the above would follow.

But we don't know the obviously correct behaviour. Why should list.__add__
return a list if the other operand is a tuple? You're assuming what I'm
asking you to justify.

int.__add__ doesn't necessarily return an int. Why should lists
be different?

I would venture to guess that most people would intuitively consider the
above behavior correct,

I dare say you are right for *some* people. After all, Perl and other
weakly-typed languages try to coerce virtually all types. I doubt it is
a majority.

simply because the information content
difference between a list versus a tuple is non-existent (outside of the
information that one is a list and the other a tuple). Why would their
types dictate coercion?

But that's what you're doing -- implicit coercion.

[1] + (1,) == [1] + [1]
(1,) + [1] == (1,) + (1,)

I don't believe there is any justification for doing such coercion for
lists and tuples.

With ints and floats, as you point out, the
reasons that type dictates coercion are obvious and mathematical. Thus,
for tuples and lists, it wouldn't make sense to consider one type taking
precendence over the other, so we fall back to position, which seems to
be the common sense approach.

I would say the commonsense approach is to refuse the temptation to guess
in the face of ambiguity. Since neither coercing lists to tuples nor
tuples to lists is more obviously correct, raising an exception is the
sensible behaviour. Let the caller choose the correct coercion to use.
 
S

Sergey Dorofeev

It's effectively a tuple with field names. I don't know when the switch
occurred (it's in 2.2, as far back as my built interpreter versions
currently go), but back in the day os.stat used to return a plain old
tuple.

posix.stat_result is CLASS, not regular tuple.
classes is the only way in python to approximate records/structs (may be
dict can be considered as record too, if we agree with strange syntaxis).
To consider tuples as struct, one must have a GREAT imagination, as tuples
functionally are _arrays_, with only difference from lists as freezeness -
the have NO filed names.
I have no idea if the schizophrenic personality of tuples will improve
with
drugs^H^H^H^H^H Python 3, but I wouldn't be at all surprised if it did.

I think the best thing is to be more democratic when asked to add two arrays
:)
 
P

Paul McGuire

Since tuples are immutable, I think of them as fixed data objects with
some simple sequential structure, as opposed to lists which are much
more dynamically accessible/updateable data containers. Back in my
relational database design days, I sometimes had to create a primary
key for a table by combining values stored in two or more columns -
neither column value alone was unique, but the combination of them
was, and so made a good retrieval index. In Python, such data pairs
would be ideally represented with tuples, in support of in-memory data
cacheing or tree indexing - for a given record, the values don't
change, so the immutability of their tupleness doesn't get in the way.

In similar vein, I've used tuples internally in my Python code as
cache keys for function memoizing. They are WORM structures - write
once, read many - built to represent the cache value, but never
updated.

With this idea of tuples as a data structure, I could reasonably
interpret this:

(1,"abc",3) + [1]

to result in (1,"abc",3,[1]) just as well as (1,"abc",3,1). But
instead of just picking one, Python complains about this, and so
forces me to explicitly use

(1,"abc",3) + tuple([1])

or

(1,"abc",3) + ([1],)

I don't think tuples are just an academic curiosity, as your post
seems to suggest.

-- Paul
 
?

=?ISO-8859-1?Q?BJ=F6rn_Lindqvist?=

I guess we differ on what is obvious. This seems obvious to me:

[1] + (1,) => [1, 1]
(1,) + [1] => (1, 1)

I agreed with you up to this point. But this seems more obvious to me:

[1] + (1,) => [1, 1]
(1,) + [1] => [1, 1]

In other languages and situations, types are widened, 1 + 1.0 = 1.0 +
1.0. And list is "wider" than tuple.
 
S

Steve Holden

J

James Stroud

BJörn Lindqvist said:
I guess we differ on what is obvious. This seems obvious to me:

[1] + (1,) => [1, 1]
(1,) + [1] => (1, 1)

I agreed with you up to this point. But this seems more obvious to me:

[1] + (1,) => [1, 1]
(1,) + [1] => [1, 1]

In other languages and situations, types are widened, 1 + 1.0 = 1.0 +
1.0. And list is "wider" than tuple.

They are widened by information content, not functionality. Tuples don't
have any more information content than lists.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,432
Messages
2,571,680
Members
48,796
Latest member
Greg L.

Latest Threads

Top