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

gah! I hate the new string syntax

10 views
Skip to first unread message

Sean 'Shaleh' Perry

unread,
Mar 1, 2001, 5:32:39 PM3/1/01
to pytho...@python.org
return ";".join(["%s=%s" % (k, params[k]) for k in params.keys()])

every day python seems to be moving closer to the line noise aspect of
coding.

Tim Roberts

unread,
Mar 2, 2001, 2:33:59 AM3/2/01
to

But join is really the only one of the string methods that comes out so
awkwardly. The rest of them are quite sensible. And, at least for now,
you do still have the traditional string.join alternative.

Wouldn't your code be slightly quicker if you used items() instead of
looking up the individual keys:

return ";".join(["%s=%s" % it for it in params.items()])
--
- Tim Roberts, ti...@probo.com
Providenza & Boekelheide, Inc.

Fredrik Lundh

unread,
Mar 2, 2001, 2:40:17 AM3/2/01
to

you're using list comprehensions and the wrong dictionary method,
and then you're complaining about string methods? ;-)

("items()" returns a key/value tuple that you can pass directly to
the formatting operator. and nobody will complain if you stick to
string.join for stuff like this...)

Cheers /F


Carl Banks

unread,
Mar 2, 2001, 4:42:56 AM3/2/01
to
Sean 'Shaleh' Perry <sha...@valinux.com> wrote:

I find it ok for methodlike functions such as split.

For unmethodlike functions such as join, I would use the old
string.join syntax (for regular strings, anyways).

"".join is just creepy.


--
CARL BANKS

"I like nothing better than a good challenge.
This is not one of them."

Robin Becker

unread,
Mar 2, 2001, 10:51:41 AM3/2/01
to
In article <0vpn79...@127.0.0.1>, Carl Banks <id...@vt.edu> writes

>Sean 'Shaleh' Perry <sha...@valinux.com> wrote:
>> return ";".join(["%s=%s" % (k, params[k]) for k in params.keys()])
>>
>> every day python seems to be moving closer to the line noise aspect of
>> coding.
>
>I find it ok for methodlike functions such as split.
>
>For unmethodlike functions such as join, I would use the old
>string.join syntax (for regular strings, anyways).
>
>"".join is just creepy.
>
>
it looks plain wrong, but would ['a','b','c'].join(';') look any better?

In fact there may be some benefit in being able to say

pathJoiner = (sys.platform=='win32' and ';' or ':').join
.....
path1 = pathJoiner([d1,d2,.....])
path2 = pathJoiner([e1,e2,.....])

--
Robin Becker

Mark Pilgrim

unread,
Mar 2, 2001, 11:26:48 AM3/2/01
to
"Fredrik Lundh" <fre...@pythonware.com> wrote in message
news:B7In6.16281$Qb7.2...@newsb.telia.net...

I recognize this code as an example from my book "Dive Into Python",
specifically http://diveintopython.org/odbchelper_join.html, and would like
to (partially) defend it in that context.

1. I used Python 1.5.x very little; I really only ramped up when 1.6/2.0 was
released. I *like* list comprehensions. I prefer them over map/lambda
because of scope issues, and I prefer them over for loops because they force
me to think Pythonically, and they emphasize Python's strengths (less code,
richer data structures). To my eyes, list comprehensions fulfill Python's
promise of being readable pseudo-code, not readable line noise. YMMV.
2. I considered using .items() and rejected it for this example, because I
didn't want to get into explaining multi-variable assignment in chapter 1.
(It is discussed later in chapter 3:
http://diveintopython.org/fileinfo_multiassign.html, including an example of
iterating through a dictionary using items().) I still believe this was the
right choice; you can't cover everything at once, even when you're talking
to smart people. However, I will add a footnote after the discussion of
this example, noting that there is an even *more* elegant way of
accomplishing the same thing using multi-variable assignment, to be covered
in chapter 3.
3. I *like* string methods, even .join(). I am aware that this puts me in a
very small minority on comp.lang.python. But I would maintain that
";".join(...) only seems odd to you because you see it as the result of a
strained migration from string.join(..., ";"), instead of seeing it with
fresh eyes. However, I may add a footnote explaining the old style
string.join, if only because new programmers will eventually come across old
code that uses it.

If current trends continue, *far more people* will learn Python 2.0 than
ever learned Python 1.x. They will all take list comprehensions and string
methods for granted, and stare at you blankly when you reminisce about the
good old days of Python 1.5.2.

-M feeling-old-and-crotchety-already-ly
You're smart; why haven't you learned Python yet?
http://diveintopython.org/

Sean 'Shaleh' Perry

unread,
Mar 2, 2001, 11:42:09 AM3/2/01
to Robin Becker, pytho...@python.org

good ole:

from string import join

l = join(';', ['a','b','c']) # thanks, this is clear and obvious

Please o' gods of python, do not deprecate the clean and obvious syntax that is
found in the string module.

Sean 'Shaleh' Perry

unread,
Mar 2, 2001, 11:40:07 AM3/2/01
to Tim Roberts, pytho...@python.org

On 02-Mar-2001 Tim Roberts wrote:
> "Sean 'Shaleh' Perry" <sha...@valinux.com> wrote:
>
>>return ";".join(["%s=%s" % (k, params[k]) for k in params.keys()])
>>
>>every day python seems to be moving closer to the line noise aspect of
>>coding.
>
> But join is really the only one of the string methods that comes out so
> awkwardly. The rest of them are quite sensible. And, at least for now,
> you do still have the traditional string.join alternative.
>
> Wouldn't your code be slightly quicker if you used items() instead of
> looking up the individual keys:
>
> return ";".join(["%s=%s" % it for it in params.items()])

That snippet came from 'Dive into Python' a book for python programmers. The
style of code in there is not anything I would want a fellow coder to follow.

The point of all of this was 'join' especially, but a few of the others (it
brother split) make for really ugly code.

" ".split(list) is another I have seen recently.

Sean 'Shaleh' Perry

unread,
Mar 2, 2001, 11:54:06 AM3/2/01
to Mark Pilgrim, pytho...@python.org
> 3. I *like* string methods, even .join(). I am aware that this puts me in a
> very small minority on comp.lang.python. But I would maintain that
> ";".join(...) only seems odd to you because you see it as the result of a
> strained migration from string.join(..., ";"), instead of seeing it with
> fresh eyes. However, I may add a footnote explaining the old style
> string.join, if only because new programmers will eventually come across old
> code that uses it.
>

if I were learning python today, I would still hate code like the above.
Turning a string literal (";") suddenly into a string object and then using its
methods is not an easy read. While trying to scan that line, my eye wants to
read the list comprehension (which is a nice feature, if compact). Then I see
the join function and it takes a moment to realize it belongs to the semicolon.

The other problem I have with this is I know too many languages. I am forced
to deal with quite a bit of perl and I actually read your book immediately
after a week's worth of working on some really evil perl code that was dumped
in my lap. SO what do I see?

";" . join() # in perl, this means concat ";" with the result of join()

Yes, I know this is an issue you learn to deal with. However, the nice, pretty
string module at least makes python look like python.

Mark, I like a lot of what I read in your book. The apihelper is a nifty idea
(if only it worked on the re module )-:). However, the coding style and
decisions seem counter to the python way. But maybe that is just me and my
hyper sensitivity to hard to read code after way too many lines of perl.

Sean 'Shaleh' Perry

unread,
Mar 2, 2001, 11:42:09 AM3/2/01
to Robin Becker, pytho...@python.org

On 02-Mar-2001 Robin Becker wrote:

good ole:

Aahz Maruch

unread,
Mar 2, 2001, 12:01:45 PM3/2/01
to
In article <97ohh2$polt0$1...@ID-77331.news.dfncis.de>,
Mark Pilgrim <f8...@yahoo.com> wrote:
>
>-M feeling-old-and-crotchety-already-ly

<pat> <pat> There, there, sonny, I know just how you feel.
--
--- Aahz (Copyright 2001 by aa...@pobox.com)

Androgynous poly kinky vanilla queer het <*> http://www.rahul.net/aahz/
Hugs and backrubs -- I break Rule 6

Nostalgia just ain't what it used to be

Mark Pilgrim

unread,
Mar 2, 2001, 1:35:09 PM3/2/01
to
"Sean 'Shaleh' Perry" <sha...@valinux.com> wrote in message
news:mailman.983552044...@python.org...

> > 3. I *like* string methods, even .join()
>
> ";" . join() # in perl, this means concat ";" with the result of join()
>
> Yes, I know this is an issue you learn to deal with. However, the nice,
pretty
> string module at least makes python look like python.

I can't help you deal with the Perl issues of your childhood, but I can
recommend a good therapist. ;)

> Mark, I like a lot of what I read in your book. The apihelper is a nifty
idea
> (if only it worked on the re module )-:). However, the coding style and

Heh heh, it does work on the re module, it's just not very helpful because
the module doesn't include docstrings for the top-level functions. The
authors are actually aware of this; see sre.py, line 41:
# FIXME: add docstrings

> decisions seem counter to the python way. But maybe that is just me and
my
> hyper sensitivity to hard to read code after way too many lines of perl.

I am always open to suggestions. I have already made some code rewrites
after discussions with readers, including several clarifications in chapter
1 and a substantial rewrite in chapter 2 (using getattr instead of eval).

A better place to discuss "Dive Into Python"-specific issues is Andamooka,
which is hosting a mirror of the book with an integrated discussion board on
each page. Unfortunately, the version of the book they have is a month out
of date (and doesn't include the getattr rewrite), but it's better than
cluttering up the newsgroup.
http://www.andamooka.org/index.pl?section=divein

-M

Donn Cave

unread,
Mar 2, 2001, 1:47:39 PM3/2/01
to
Quoth "Mark Pilgrim" <f8...@yahoo.com>:

| "Fredrik Lundh" <fre...@pythonware.com> wrote in message
| news:B7In6.16281$Qb7.2...@newsb.telia.net...
|> Sean 'Shaleh' Perry wrote:
|> > return ";".join(["%s=%s" % (k, params[k]) for k in params.keys()])
|> >
|> > every day python seems to be moving closer to the line noise aspect of
|> > coding.
|>
|> you're using list comprehensions and the wrong dictionary method,
|> and then you're complaining about string methods? ;-)
|>
|> ("items()" returns a key/value tuple that you can pass directly to
|> the formatting operator. and nobody will complain if you stick to
|> string.join for stuff like this...)
|
| I recognize this code as an example from my book "Dive Into Python",
| specifically http://diveintopython.org/odbchelper_join.html, and would like
| to (partially) defend it in that context.
|
| 1. I used Python 1.5.x very little; I really only ramped up when 1.6/2.0 was
| released. I *like* list comprehensions. I prefer them over map/lambda
| because of scope issues, and I prefer them over for loops because they force
| me to think Pythonically, and they emphasize Python's strengths (less code,
| richer data structures). To my eyes, list comprehensions fulfill Python's
| promise of being readable pseudo-code, not readable line noise. YMMV.

Pseudo-code is the language you don't have to know, to understand,
right? Familiar symbols, unambiguous syntax. Could you articulate
your thoughts on this, how do list comprehensions improve on their
alternatives, there?

What does "think Pythonically" mean to you? What are you thinking of
when list comprehensions make you cite "less code, richer data structures"
as a strength of Python? Can you talk us crotchety old-timers through this?

| 3. I *like* string methods, even .join(). I am aware that this puts me in a
| very small minority on comp.lang.python. But I would maintain that
| ";".join(...) only seems odd to you because you see it as the result of a
| strained migration from string.join(..., ";"), instead of seeing it with
| fresh eyes. However, I may add a footnote explaining the old style
| string.join, if only because new programmers will eventually come across old
| code that uses it.
|
| If current trends continue, *far more people* will learn Python 2.0 than
| ever learned Python 1.x. They will all take list comprehensions and string
| methods for granted, and stare at you blankly when you reminisce about the
| good old days of Python 1.5.2.

I bet when people see ";".join(...) with fresh eyes, they still
find it strained. This is not about the old school vs. the new,
it's a serious question of how people understand computer programming
languages. Is it like natural language? Can we think about it in
sort of mathematical terms, like symmetry etc.? Does everyone handle
it basically the same way?

For sure, more people will learn 2.x. But they're here because of
the success of previous versions, not because 2.x was finally good
enough for them to get on board. It doesn't tell us anything about
the value of features introduced in 2.x.

Donn Cave, do...@u.washington.edu

Sean 'Shaleh' Perry

unread,
Mar 2, 2001, 1:36:45 PM3/2/01
to Tim Peters, pytho...@python.org

On 02-Mar-2001 Tim Peters wrote:
> [Sean 'Shaleh' Perry]

>> good ole:
>>
>> from string import join
>>
>> l = join(';', ['a','b','c']) # thanks, this is clear and obvious
>>
>> Please o' gods of python, do not deprecate the clean and obvious
>> syntax that is found in the string module.
>
> Sean, that claim of "obvious" would have been a lot more convincing if you
> had managed to remember the correct order of string.join's arguments <wink>.
>

As I said in other mails, forgive me, brain dead from reading WAY too much perl
this week.

Tim Peters

unread,
Mar 2, 2001, 1:30:54 PM3/2/01
to pytho...@python.org
[Sean 'Shaleh' Perry]

> good ole:
>
> from string import join
>
> l = join(';', ['a','b','c']) # thanks, this is clear and obvious
>
> Please o' gods of python, do not deprecate the clean and obvious
> syntax that is found in the string module.

Sean, that claim of "obvious" would have been a lot more convincing if you

Mark Pilgrim

unread,
Mar 2, 2001, 3:13:20 PM3/2/01
to
"Donn Cave" <do...@u.washington.edu> wrote in message
news:97opsb$nhu$1...@nntp6.u.washington.edu...
> Quoth "Mark Pilgrim" <f8...@yahoo.com>:

> | 1. I used Python 1.5.x very little; I really only ramped up when 1.6/2.0
was
> | released. I *like* list comprehensions. I prefer them over map/lambda
> | because of scope issues, and I prefer them over for loops because they
force
> | me to think Pythonically, and they emphasize Python's strengths (less
code,
> | richer data structures). To my eyes, list comprehensions fulfill
Python's
> | promise of being readable pseudo-code, not readable line noise. YMMV.
>
> Pseudo-code is the language you don't have to know, to understand,
> right? Familiar symbols, unambiguous syntax. Could you articulate
> your thoughts on this, how do list comprehensions improve on their
> alternatives, there?

Well, list comprehensions are unambiguous in the sense that they are a
specific syntax -- they map a list into another list, and (possibly) filter
out some elements along the way. Using a for loop and an if statement to do
this is ambiguous in the sense that you could use that physical code
structure for anything, not just for accomplishing the logical goal of
mapping a list. Glancing at a for loop, you couldn't just say "this bit of
code maps a list into another list" without examining the code thoroughly
and making sure that's really what it was doing, that there weren't any side
effects along the way, etc. Glancing at a list comprehension, you instantly
know what it is, because the syntax is specific instead of general. (Note
this does not mean you know what it *does*, just that you can reasonably
rule out lots of things that it doesn't do.)

> What does "think Pythonically" mean to you? What are you thinking of
> when list comprehensions make you cite "less code, richer data structures"
> as a strength of Python? Can you talk us crotchety old-timers through
this?

For example, I recently had to write a Python script that locked ClearCase
VOBs (it is not required to understand what those are to follow this
example). You can do this on the command line: ("cleartool lock vob1 vob2
vob3..."), but the only way to get the list of VOBs is with another command
line tool ("cleartool lsvob -l"), which returns the VOB name on one line
("Tag: <vob>") plus lots of information we don't care about, like this:

Tag: /vobs/intranet
Global path: ...
Server host: ...
Vob on host: ...
...

Tag: /vobs/project
Global path: ...
Server host: ...
Vob on host: ...
...

If you think of this output as one long string, you can write a for loop
that searches for each "Tag:" and parses out the rest of the line to get a
single VOB name. But don't do that, that's Visual Basic thinking!
(Actually in my case it's Powerbuilder thinking, but it's just as bad.)
Instead, I force myself to think of the output as a list of strings, where
each line is an element. This is very easy using readlines():

>>> output = os.popen("cleartool lsvob -l").readlines()

Now I think: OK, I have a list of lines, but I only want some of them -- the
ones starting with "Tag:" -- and I want to throw the rest away. I could do
this with a for loop, but that's (a) more typing, and (b) more ambiguous
(see above). Since I have the lines in a list, I can use a list
comprehension:

>>> [line for line in output if line[:4]=='Tag:']
['Tag: /vobs/intranet\\012', 'Tag: /vobs/project\\012']

Now I think: OK, I have a list of the lines I want, but I just want the
name, not the "Tag:" prefix or all the whitespace.

>>> vobs = [line.replace('Tag:', '').strip() for line in output if
line[:4]=='Tag:']
>>> vobs
['/vobs/intranet', '/vobs/project']

Now I think: great, I have a list of VOBs, now I need them space-separated
and integrated into the rest of my command line:

>>> "cleartool lock %s" % " ".join(vobs)
'cleartool lock /vobs/intranet /vobs/project'

And that's what I call thinking Pythonically. YMMV.

-M

Carl Banks

unread,
Mar 2, 2001, 11:41:14 AM3/2/01
to
Robin Becker <ro...@jessikat.fsnet.co.uk> wrote:
> In article <0vpn79...@127.0.0.1>, Carl Banks <id...@vt.edu> writes
>>Sean 'Shaleh' Perry <sha...@valinux.com> wrote:
>>> return ";".join(["%s=%s" % (k, params[k]) for k in params.keys()])
>>>
>>> every day python seems to be moving closer to the line noise aspect of
>>> coding.
>>
>>I find it ok for methodlike functions such as split.
>>
>>For unmethodlike functions such as join, I would use the old
>>string.join syntax (for regular strings, anyways).
>>
>>"".join is just creepy.
>>
> it looks plain wrong, but would ['a','b','c'].join(';') look any better?

No, but string.join(['a','b','c'],';') does look better, IMO.


> In fact there may be some benefit in being able to say
> pathJoiner = (sys.platform=='win32' and ';' or ':').join
> .....
> path1 = pathJoiner([d1,d2,.....])
> path2 = pathJoiner([e1,e2,.....])

Sure. I'm not saying join should not be a method, only that I prefer
the function invocation as a matter of style. Most other string
methods are ok, but this one I find supremely weird.

Magnus Lie Hetland

unread,
Mar 2, 2001, 4:31:33 PM3/2/01
to
"Mark Pilgrim" <f8...@yahoo.com> wrote in message
news:97oupq$qijrh$1...@ID-77331.news.dfncis.de...
[snip]

> >>> [line for line in output if line[:4]=='Tag:']
> ['Tag: /vobs/intranet\\012', 'Tag: /vobs/project\\012']
>
> Now I think: OK, I have a list of the lines I want, but I just want the
> name, not the "Tag:" prefix or all the whitespace.
>
> >>> vobs = [line.replace('Tag:', '').strip() for line in output if
> line[:4]=='Tag:']
> >>> vobs
> ['/vobs/intranet', '/vobs/project']

I can't resist fiddling with little snippets of code... Why don't you
use:

>>> vobs = [line[4:-1] for line in output if line[:4] == 'Tag:']

Oh, well...

--

Magnus Lie Hetland http://www.hetland.org

"Reality is what refuses to disappear when you stop
believing in it" -- Philip K. Dick

Magnus Lie Hetland

unread,
Mar 2, 2001, 4:34:37 PM3/2/01
to
"Sean 'Shaleh' Perry" <sha...@valinux.com> wrote in message
news:mailman.983551204...@python.org...
[...]

> The point of all of this was 'join' especially,
> but a few of the others (it
> brother split) make for really ugly code.
>
> " ".split(list) is another I have seen recently.
>

What does *this* mean, then? (AFAIK it isn't valid
Python unless list is a character...)

Mark Pilgrim

unread,
Mar 2, 2001, 5:45:33 PM3/2/01
to
in article 97p3mh$bkm$1...@tyfon.itea.ntnu.no, Magnus Lie Hetland at
m...@idi.ntnu.no wrote on 3/2/01 4:31 PM:

> "Mark Pilgrim" <f8...@yahoo.com> wrote in message
> news:97oupq$qijrh$1...@ID-77331.news.dfncis.de...
> [snip]
>>>>> vobs = [line.replace('Tag:', '').strip() for line in output if
>> line[:4]=='Tag:']
>>>>> vobs
>> ['/vobs/intranet', '/vobs/project']
>
> I can't resist fiddling with little snippets of code... Why don't you
> use:
>
>>>> vobs = [line[4:-1] for line in output if line[:4] == 'Tag:']

Actually, for the same reason the original poster complained about the
original code snippet: my version reads more like natural language. (It
also, I realized after posting, assumes that the VOB name doesn't contain
'Tag:', which I know it won't, but that wasn't clear from the example.)
"For each line in the output, if the line starts with 'Tag:', cut out the
'Tag:' part and strip the whitespace, and give me a list of all of those."
That's a pretty direct mapping from code to description.

My original point, in case it got lost in the details, was that I like list
comprehensions because they force me to think Pythonically. By that I mean
thinking in terms of the things that Python is good at, like lists and
dictionaries. These are rich data structures with lots of built-in
capabilities, and if I don't use them, I may as well go back to programming
in Powerbuilder: writing WHILE loops to do progressive searches through
strings when I really want something like the above example, using SELECT
CASE statements for jump tables when all I really want is a dictionary of
functions, and so forth.

John W. Baxter

unread,
Mar 2, 2001, 5:50:22 PM3/2/01
to
In article <97opsb$nhu$1...@nntp6.u.washington.edu>,
Donn Cave <do...@u.washington.edu> wrote:

> I bet when people see ";".join(...) with fresh eyes, they still
> find it strained. This is not about the old school vs. the new,
> it's a serious question of how people understand computer programming
> languages. Is it like natural language? Can we think about it in
> sort of mathematical terms, like symmetry etc.? Does everyone handle
> it basically the same way?

Take two APLs, or a liberal dose of John Iverson, and all will be well.
;-)

Fortunately, it's not the only way to join.

--John

--
John W. Baxter Port Ludlow, WA USA jwb...@scandaroon.com

Russell E. Owen

unread,
Mar 2, 2001, 5:41:30 PM3/2/01
to
In article <mailman.983485923...@python.org>,

Mostly I think string methods are a great idea. One thing that annoyed
me about python early on was the plethora of global functions that made
more sense to me (a smalltalk lover, I admit) as methods. So overall I'm
very pleased to see the new string methods.

However, I do agree that join is not intuitive. I believe the problem
(at least for the way I look at it) is that join should be a list
method, not a string method. I.e.:

joined_string = ['a', 'b'].join(', ')

makes a lot of sense to me. The current join string method does not.

-- Russell

Sean 'Shaleh' Perry

unread,
Mar 2, 2001, 5:34:29 PM3/2/01
to Magnus Lie Hetland, pytho...@python.org

On 02-Mar-2001 Magnus Lie Hetland wrote:
> "Sean 'Shaleh' Perry" <sha...@valinux.com> wrote in message
> news:mailman.983551204...@python.org...
> [...]
>> The point of all of this was 'join' especially,
>> but a few of the others (it
>> brother split) make for really ugly code.
>>
>> " ".split(list) is another I have seen recently.
>>
>
> What does *this* mean, then? (AFAIK it isn't valid
> Python unless list is a character...)
>

it was a snippet of code I saw somewhere. It turns out the person has it
backwards (thankfully).

The actual code would be:

s = 'This is a string'
s.split(" ")

which makes some amount of sense, although I still like the string module
version better.

Carel Fellinger

unread,
Mar 2, 2001, 7:12:50 PM3/2/01
to
Mark Pilgrim <f8...@yahoo.com> wrote:
...

>>>> output = os.popen("cleartool lsvob -l").readlines()
...

>>>> [line for line in output if line[:4]=='Tag:']
...

>>>> vobs = [line.replace('Tag:', '').strip() for line in output if
> line[:4]=='Tag:']
...

>>>> "cleartool lock %s" % " ".join(vobs)
> 'cleartool lock /vobs/intranet /vobs/project'

> And that's what I call thinking Pythonically. YMMV.

nai, that's unix thinking, like with

$ cleartool lock `cleartool lsvob -l | grep ^Tag: data | cut -c 6-`

--
groetjes, carel

Paul Jackson

unread,
Mar 2, 2001, 11:52:32 PM3/2/01
to

Sorry - couldn't resist the following ...

Carel wrote:
> $ cleartool lock `cleartool lsvob -l | grep ^Tag: data | cut -c 6-`

I think the 'data' (2nd grep arg) should be removed.

And (groan) yet another way to write this would be:

cleartool lsvob -l | awk '$1 == "Tag:" { print $2; }' | xargs cleartool lock

This way avoids assumptions of the exact number of spaces in
the lsvob output, and works if more vob's need locking than fit
in the system's MAXARGS (God help you if you have a ClearCase
installation _that_ big!).

... I write this trusting that everyone else on this thread has
more sense than to follow this up with yet more ways to write
shell one-liners ... clearly I lack such sense ...

--
I won't rest till it's the best ...
Manager, Linux System Software
Paul Jackson <p...@sgi.com> 1.650.933.1373

Donn Cave

unread,
Mar 3, 2001, 12:57:41 AM3/3/01
to
Quoth Mark Pilgrim <f8...@diveintopython.org>:
...

| My original point, in case it got lost in the details, was that I like list
| comprehensions because they force me to think Pythonically. By that I mean
| thinking in terms of the things that Python is good at, like lists and
| dictionaries. These are rich data structures with lots of built-in
| capabilities, and if I don't use them, I may as well go back to programming
| in Powerbuilder: writing WHILE loops to do progressive searches through
| strings when I really want something like the above example, using SELECT
| CASE statements for jump tables when all I really want is a dictionary of
| functions, and so forth.

Ah. You know, not only am I a grizzled, hide-bound veteran of old
python versions beyond reckoning, I'm a UNIX programmer.

I have no idea what it's like to use Visual Basic, I have never
even heard of Powerbuilder. Like many of my gnarly old brethren,
I fooled around with Scheme dialects, Tcl and whatever came along,
until eventually I think it was Ken Manheimer was kind enough to
personally mail me a clue about Python, but the big competition
in our world was and still is Perl. Most of us have been there,
and when we ask ourselves what Python is about, Perl is a huge
part of the background.

If you haven't already, you must learn about Perl. You don't
need to write programs, but along with some reading about the
language you want to see what happens when people actually write
Perl to do stuff, not for publication. This is a language that
has the lists and the dictionaries and lots more syntactical
features that save you a bundle of typing - Python is tediously
verbose by comparison. Many people love Perl. You may find that
you do, too, there's no reason to expect otherwise. But it's
important to recognize that there is a huge crowd of people who
swim upstream to use Python instead, and it's not just because
we have to be different, it's not because we want to use Zope
or our boss twisted our arm to write in Python. It's certainly
not because Python is more powerful, in the sense you have been
talking about. I'm beating around the bush a little, because
I don't know how to talk about it directly in a way that really
does justice to it, but I think if you get it, you'll find it
more interesting than rich feature sets. Or maybe not, I don't
know, I guess it's not for everyone, but for myself, I want to
challenge your notion of what it is to think Pythonically.

Donn Cave, do...@oz.net

Kirby Urner

unread,
Mar 3, 2001, 1:41:20 AM3/3/01
to
Donn Cave <do...@oz.net> wrote:

>Quoth Mark Pilgrim <f8...@diveintopython.org>:

>know, I guess it's not for everyone, but for myself, I want to
>challenge your notion of what it is to think Pythonically.
>
> Donn Cave, do...@oz.net

Personally speaking, I found Pilgrim's defense of list
comprehensions cogent, and I think his 'Dive Into Python'
is pretty good. So maybe he should have used {}.items()
more often -- I bet he will in future.

I'm another one of those who did NOT come to Python from an
extensive career in UNIX and related paraphernalia (awk yak
gak...). I've got Linux in a partition and visit it once in
a while -- glad it's there, happy to see that world expanding
by leaps and bounds.

My first exposure to computing was via the mainframe in college,
an IBM 360/370 VM with APL terminals scattered around campus.
In my psyche, Python is a lot like APL, but with the little
geeky greek-looking symbols replaced by more ordinary-looking
characterstrings.

I've studied Perl to a beginner level, but I think it's somewhat
ugly to look at. Whereas I'm sure its crypto-compression
attracts a lot of people, I find Python better because cleaner
somehow (simpler) -- dunno if that's what you were getting at
(your opinion sounds more expert/refined). But that in no way
means I think it's a "language war" with Perl -- I hope Perl
sticks around forever, like Python will.

Pilgrim's use of list comprehensions wherever suitable doesn't
seem a dive into an arcane or cryptic style. The 'map' thing
was cumbersome, because if your function had two or more
parameters, but you wanted to hold one or more of them constant,
you had do to things like:

>>> def f(a,b): return a+b

>>> f(1,1)
2
>>> g = lambda x: f(1,x)
>>> map(g,[1,2,3,4]) # or collapse this + above into one line
[2, 3, 4, 5]

or

map(f,[1]*4,[1,2,3,4])
[2, 3, 4, 5]

But with list comprehension, you just go:

[f(1,x) for x in [1,2,3,4]]
[2, 3, 4, 5]

That's a lot less "beating around the bush" to get that one
argument to hold at 1, letting the other vary.

Kirby


Mark Pilgrim

unread,
Mar 3, 2001, 2:06:52 AM3/3/01
to
in article 97q14l$jbi$0...@216.39.151.169, Donn Cave at do...@oz.net wrote on
3/3/01 12:57 AM:

> I have no idea what it's like to use Visual Basic, I have never
> even heard of Powerbuilder.

Heh heh, I'd love to go back to my previous employer and quote you on that.
They thought Powerbuilder was the right tool for every job.

> verbose by comparison. Many people love Perl. You may find that
> you do, too, there's no reason to expect otherwise. But it's

I have had just enough experience with Perl to know that I don't want any
more. ;)

> important to recognize that there is a huge crowd of people who
> swim upstream to use Python instead, and it's not just because
> we have to be different, it's not because we want to use Zope
> or our boss twisted our arm to write in Python. It's certainly
> not because Python is more powerful, in the sense you have been
> talking about.

Oddly enough, my current boss did twist my arm to learn Python, but I
realize that that's the exception. But I do now understand better why
people have called my coding style "dense" (meaning "too tightly packed"),
"line noise", etc. Coming from Perl, I guess Python would be a breath of
fresh air precisely because it's more verbose, less dense, more readable.
But I came at Python from a different angle, after years of being forced to
use inferior, less powerful, less expressive languages which we were pushing
beyond their limits. (We had to write code from scratch to parse the
command line, because there was nothing like sys.argv. We had to write
Windows API calls to get a directory listing because we had no os.listdir
and the only built-in function to do it would only put the results into a
graphical listbox. We had no regular expression parsing whatsoever. Etc.)
I love that, in Python, I can write in three lines of code what would take
an entire page in Powerbuilder. If you want to quibble and say that it
would be more Pythonic to write it in four lines of code, that's fine, we
can both happily co-exist.

> know, I guess it's not for everyone, but for myself, I want to
> challenge your notion of what it is to think Pythonically.

Actually, to me, rich data structures are a minor part of thinking
Pythonically; they're just what the original example was about in this
thread. A much more important part is introspection, which I cover in depth
in chapter 2 of my book (http://diveintopython.org/apihelper_divein.html).
Looking back on it now, I can't believe I ever put up with a language where
you had to choose between dynamically constructing a method name and getting
a return value (*); where you couldn't find out what methods a class had;
where you couldn't get access to the stack trace when something went wrong.

(*) Fellow Powerbuilder survivors will remember that TriggerEvent, which
allows you to call an event by name, doesn't return the event's return
value, and all other ways of calling a method require you to know the method
name at design time. If you were wondering why I poke fun at Powerbuilder
in my book, that's why. That, and the
directory-listing-into-a-graphical-listbox function; that was classic.

Mark Pilgrim

unread,
Mar 3, 2001, 2:55:54 AM3/3/01
to
in article 7k31at0hbkuqgjtns...@4ax.com, Kirby Urner at
ur...@alumni.princeton.edu wrote on 3/3/01 1:41 AM:

> Pilgrim's use of list comprehensions wherever suitable doesn't
> seem a dive into an arcane or cryptic style. The 'map' thing
> was cumbersome, because if your function had two or more
> parameters, but you wanted to hold one or more of them constant,

Heh heh, he said "Dive Into". :)

I agree completely with Kirby. I mentioned this in passing earlier in this
thread, but it bears repeating: the map/lambda solution is awkward no matter
how you cut it. Consider the example of getting a list of fully qualified
pathnames of the contents of a directory, something I do all the time. You
could certainly do this with map:

>>> map(lambda f, dirname=dirname: os.path.join(dirname, f),
os.listdir(dirname))

That's awkward because of the "dirname=dirname" hack required by the lack of
nested scopes. (Yes, yes, I know this will be solved in Python
2.1^H^H^H2.2^H^H^H2.3.) Or you could break it up into two steps, like this:

>>> fileList = os.listdir(dirname)
>>> map(os.path.join, [dirname]*len(fileList), fileList)

That's awkward because of the list multiplication, and it has to be done in
two steps because you don't know how long the list will be ahead of time.
Or you could just use a list comprehension, like this:

>>> [os.path.join(dirname, f) for f in os.listdir(dirname)]

To me, that says "for each of the files in this directory, make a full
pathname out of it, and give me a list of all of those." I don't know what
the map examples say, other than "I'm trying to do something simple and this
language is making it hard." If I wanted to feel like that, I'd go back to
Powerbuilder.

Tim Peters

unread,
Mar 3, 2001, 5:25:15 AM3/3/01
to pytho...@python.org
[Donn Cave]
> ...

> Pseudo-code is the language you don't have to know, to understand,
> right?

No such language.

> Familiar symbols, unambiguous syntax. Could you articulate
> your thoughts on this, how do list comprehensions improve on their
> alternatives, there?

Donn, listcomps are a minor variant of set-builder notation; in wide use at
latest since the 19th century; in America, it appears this is normally
introduced in the 6th or 7th grades (ages 11-12, for those of you in inferior
countries <wink>). Search the web, and you'll find intros sprinkled with
cheery encouragements like:

Math is fun ...
and who can doubt it ...
If we have ...
no doubt about it!!!

(quoted without permission from Miss LeBrocq's Sixth Grade Math Syllabus).

Try explaining compositions of higher-order functions to an 11-year old.
That's "their alternatives" in Python practice -- at least to judge from
Kirby's map-happy code <wink>.

if-listcomps-were-a-bad-idea-i-vote-we-send-the-language-straight-
to-hell-ly y'rs - tim


chris

unread,
Mar 3, 2001, 7:52:35 AM3/3/01
to
> at latest since the 19th century; in America, it appears this is normally
> introduced in the 6th or 7th grades (ages 11-12, for those of you in
> inferior countries <wink>

In Scotland that kind of stuff is pre-School! <wink-back>

Chris

Donn Cave

unread,
Mar 3, 2001, 1:08:43 PM3/3/01
to
I used to use map, filter, reduce, but a couple of years ago
I gave that up because I felt it would make my code harder
for other people to read. An explicit loop is better.

Donn Cave, do...@oz.net

Kirby Urner

unread,
Mar 3, 2001, 2:05:12 PM3/3/01
to
Donn Cave <do...@oz.net> wrote:

I think it's possible to go overboard with the 'functional
programming' type operators (if we can call 'em that), but
I prefer to use them within reason vs. not use them at all
-- and I think the new list comprehension syntax makes the
code even more readable.

For example, when doing sigma (sum of terms), passing in
the function and lower/upper term indices, you could write:

from operator import add # used below
def f(x): return x*x # example function

def sigma(f,stop,start=1):
result = 0
for i in range(start,stop+1):
result += f(i)
return result

or

def sigma(f,start,stop,start=1):
return reduce(add,map(f,range(start,stop+1)))

or

def sigma(f,stop,start=1):
return reduce(add,[f(x) for x in range(start,stop+1)])

This last is my personal favorite. I don't find
it harder to read than the first.

And I _really_ like the combination of functions
below for listing out numbers < n that are relatively
prime to n:

def gcd(n,m):
"""
Euclid's Algorithm for GCD
"""
while m:
n,m = m,n%m
return n

def relprimes(n):
"""
List coprimes < n
"""
return [x for x in range(1,n) if gcd(n,x)==1]

So neat, so clean! Pythonic math is kewl.

Kirby

Steve Holden

unread,
Mar 3, 2001, 2:45:27 PM3/3/01
to
"Paul Jackson" <p...@sgi.com> wrote in message
news:97ptag$81s65$1...@fido.engr.sgi.com...

>
> Sorry - couldn't resist the following ...
>
[YASOL]

>
> ... I write this trusting that everyone else on this thread has
> more sense than to follow this up with yet more ways to write
> shell one-liners ... clearly I lack such sense ...
>
Pythonic thinking at its best ;-)

"""From personal experience I have to say that Python users are a great
bunch of people. Flames are noticeably less frequent on comp.lang.python
than other language newsgroups, despite recent increases in volume. Whether
this comes from using the language, or the group is effective in socializing
its members, or whether Python just naturally attracts a particular type of
personality is difficult to say. The list is also exceptionally welcoming to
newcomers, and patiently revisits topics that could be answered by a search
of the FAQ."""

[An anthropological note on Python users: forthcoming]

Do you mind if I quote you, with appropriate attribution?

regards
Steve

Steve Holden

unread,
Mar 3, 2001, 3:19:05 PM3/3/01
to
"chris" <chri...@btinternet.com> wrote in message
news:tN5o6.2746$eH3.14913@NewsReader...

Ha! As an Englishman married to a Scot I'm not going to let you get away
with that one: this is classic Scottish braggadocio [I expect Italian
education form tne martellibot about that]. Brass neck, as we simple
Yorkshire folk would term it.

Still, at least we can remind all that Scotland and England are different
countries on c.l.py.

Lest people might think this is intended as criticism rather than humo(u)r,
I hasten to add that I lived in Scotland for three years before moving to
the USA, and found the Scots to be extraordinarily warm and generous people.

As I put it to a taxi-driver on Scotland recently who asked me how I got on
in Scotland "I find that once we get past 'Engl***h' and 'bas***d' we can
get on all right". He correctly pointed out that this was a racist remark,
but we got on fine and agreed that nobody was offended.

So, for the record, they don't get their mathmatics degrees until fourth
grade in Scotland.

coming-from-the socialist-people's-republic-of-yorkshire-and-therefore-
not-quite-as-english-as-others-we-won't-mention-y'rs - steve

Alex Martelli

unread,
Mar 3, 2001, 3:29:55 PM3/3/01
to
"Russell E. Owen" <ow...@astrono.junkwashington.emu> wrote in message
news:97p7iq$kk2$1...@nntp6.u.washington.edu...
[snip]

> However, I do agree that join is not intuitive. I believe the problem
> (at least for the way I look at it) is that join should be a list
> method, not a string method. I.e.:
>
> joined_string = ['a', 'b'].join(', ')
>
> makes a lot of sense to me. The current join string method does not.

This seems to be a widespread opinion, and I've already tried
to explain why my take on it differs, but that was a few months
ago, and apparently the current crop of discussants hasn't read
those discussions, so, let's give it one more spin.

Python does not have multi-methods: it's a single-dispatch
language. Thus, quite apart from minor issues of syntax sugar,
there is ONE important difference between:

paak.join(klop) # form 1
klop.join(paak) # form 2
amodule.join(paak, klop) # form 3

Form 1 states: this .join call CAN be directly polymorphic on
(==directly dispatch on) paak, but NOT on klop -- if it's at
all polymorphic on klop, it must be by accessing it through
some standard interface ('interfaces' are not formalized in
Python, or Smalltalk, but, informally, they do exist and are
widely used -- "this argument must be a file-like object
and implement method write", "this must be a sequence",
etc).

Form 2 states the reverse: this .join call CAN be directly
polymorphic on (==directly dispatch on) klop, but NOT on
paak -- if it's at all polymorphic on paak, it must be by
accessing it through some standard interface.

Form 3 states that this call (on a module function) is not
directly polymorphic on _either_ klop or paak, though it
may access either or both through standard interfaces and
thus attain a (constrained) degree of polymorphism on
either or both of them.

It would be different in a multi-dispatch language, of
course, but Python isn't one (nor is Smalltalk).

So, when one states "join should be a method of klop, not
of paak" ('form 2 is better than form 1'), one is really
stating something like...: "this .join may more easily need
to be generally-polymorphic on klop, while, if it needs any
polymorphism on paak, it will more reasonably be able to
obtain it indirectly by accessing paak through some standard
interface".
If one expresses a preference for form 3 over either 1 or 2,
then one is stating that general polymorphism is not very
necessary on either argument, that standard interfaces
will do the job satisfactorily enough if any polymorphism at
all is needed.

I hope we do agree so far -- it doesn't seem to me that,
so far, there is really anything contentious or debatable
in what I've written. If one considers syntax sugar in se
and per se more important than polymorphic semantics,
of course, then one _might_ think my assertions so far
are contentious and debatable -- but I wouldn't be very
interested in debating them: for me, the importance of
substance always dominates that of mere form... I'd
rather read a great novel in a poor, cheap binding, than
trash hand-bound in the best-quality leather. Those who
disagree are welcome to their opinions (and particularly
their expensively-bound trash literature!-) but we'll never
manage to convince each other of anything anyway.


So, back to the specific discussion: Python 2 implicitly
asserts "when a string ``joiner'' is used to join the items
in a sequence of strings, it's more important than the
method be polymorphic on the joiner-object; polymorphism
on the sequence of strings can be obtained indirectly by
accessing it through a standard interface".

You guys who disagree are implicitly asserting that full
fledged polymorphism over the sequence of strings being
joined is more important -- than either no polymorphism
at all is needed on the joiner object, or that what is needed
can be obtained by accessing it through a standard interface.

So, let's compared these implicit underlying assertions --
what kind of polymorphism is needed and where.


Say that I'm implementing a sequence-like object. Would
having .join as a part of the set of methods I must write
be an _advantage_ to me? As things stand now, to "be a
sequence" I must just implement __getitem__ in the
appropriate manner -- accepting an index from 0 to N-1,
and raising IndexError for indices outside the range -- and
maybe implement __length__ to return N. With this small
amount of effort, I gain the ability to be used as sequence
in any existing context -- from the for statement onwards.

For example, if my object gets passed to a file-like object's
writelines method, then, voila, my string items, which I
return in sequence from __getitem__, get 'written' to the
file-like object one after another, in order -- I don't have
to do anything peculiar to allow that, nor am I given any
chance to interfere with the procedure in case of need --
that's what it means to get polymorphism by being accessed
through a standard interface, rather than direct, generalized
polymorphism. The standard interface makes you work much
less (you implement it once, and it comes in handy for many
kinds of client code), but it gives you no say on what is to
happen in _specific_ situations -- you're not even informed
for what exact purpose / in what exact contect your standard
interface's methods are being called.

I'm pretty happy not having to worry about "how are my
items to be joined [written one after another] when I am
passed to writelines", etc -- I implement the sequence
standard interface, and I get 'for free' the ability of being
polymorphically used as a sequence "everywhere". Cool!

At least in all use cases I've ever found, my object is
quite happy NOT being told 'your items are to be written
one after another to this file-like object, do whatever is
appropriate' -- rather, it's asked for its items one after
the other, and the asker does whatever is appropriate --
the sequence object's task is JUST to be a sequence, to
present the items appropriately and let it be known when
there are no more.

Is the case 'your items are to be made into a single
string by being joined by this joiner-object' -- the join
method -- all that different from the writelines method
case? I don't think so -- why would I _want_ to do
something different and peculiar when what is to be
done with my items (one after another in sequence)
is to be concatenated into a string rather than written
into a file? In either case I'll just present my items
in sequence, one after the other, and whatever object
is asking for them will do whatever operation it needs
to do. So, it's quite appropriate for the sequence to be
passed as an argument to .writelines, .join, etc; all the
polymorphism needed on the sequence object is well
handled by accessing it through the standard sequence
interface.


What about the joiner object? Could IT be accessed
through a standard interface, rather than provide the
general polymorphism via dispatch?
Well, WHAT standard interface would that be? What
methods would it provide, and for what purposes?
I can't think of any appropriate interface except one
with a .join method -- which would rather beg the
question, since a .join method is exactly what we're
trying to design...! We could _name_ it differently
in a standard interface, but, what for? We may as
well accept the name 'join'.

So, IF we need any polymorphism at all on the part
of the joiner-object, it had better be general dispatch
polymorphism -- either that, or no polymorphism at
all. Well, IS any polymorphism at all useful on the
joiner object...?


As it happens, it is. As for other string methods, for
example, the fact that .join is a method of string
objects (and, polymorphically, Unicode strings) saves
the type-switching that a module-level function would
have to do, each and every time, to distinguish whether
single-byte character strings or Unicode ones are
involved. But, there are other opportunities -- consider,
for example:

class MixedJoiner:
def __init__(self, joiner1, joiner2):
self.joiner1 = joiner1
self.joiner2 = joiner2
def join(self, sequence):
return joiner2.join((
joiner1.join(sequence[:-1]),
sequence[-1]))

Now, if we get sequences of strings and want to join
them in such wise that the LAST joining uses a different
joiner than the others, we just have to instantiate the
appropriate MixedJoiner instance and use it:

>>> comma_and = MixedJoiner(', ',' and ')
>>> print comma_and.join(('wine','women','song'))
wine, women and song
>>> print comma_and.join(('spam','butter','bacon','eggs'))
spam, butter, bacon and eggs

Now, any piece of client code written to use a joiner
object polymorphically through its join method will
work just as well with our MixedJoiner instance:

def print_joined(joiner, *sequence):
print joiner.join(sequence)

we can now call
>>> print_joined(comma_and, 'wine', 'women', 'song')
to get the output of:
wine, women and song
just as we call it to get the printing to use space-joining:
>>> print_joined(' ','wine', 'women', 'song')
the latter emitting, of course:
wine women song


So, since we want general polymorphism on the joiner
object, but are quite content with polymorphism through
the standard sequence interface on the sequence object,
it is _just right_ that .join be a method on the joiner
object (e.g., a string) and that it take the sequence of
string to be joined as its argument.

I have not heard ANY _technical_ arguments opposed to
this last time the discussion went around -- nothing but
vague aesthetic, "it should be the other way", "I find it
ugly" kind of complaints. Unless and until further notice,
then, I class these together with the complaints of people
who dislike 0-based indexing, on similar vague bases -- as
0-based indexing _works_ better than 1-based, then, for
me, it is a superior choice. Aesthetics is in the eye of the
beholder, and the beholder _can_ be retrained and grow
a 'technically better and more appropriate' view of the
world -- one that will let him or her 'see' as 'beautiful'
those approaches which offer maximal effectiveness and
simplicity. Technical issues such as where we want general
polymorphism versus standardized-interface access, just
like ones about arithmetic, tend to be more persistent, as
well as applying more generally, and impersonally, while
aesthetics are more subjective, individual, and fickle.


Alex

D. Michael McFarland

unread,
Mar 3, 2001, 4:37:30 PM3/3/01
to
"Steve Holden" <sho...@holdenweb.com> writes:

> Lest people might think this is intended as criticism rather than humo(u)r,
> I hasten to add that I lived in Scotland for three years before moving to
> the USA, and found the Scots to be extraordinarily warm and generous people.

Well, sure, after my ancestors left at sword-point. We go back for a
visit from time to time, though, so be careful.

> So, for the record, they don't get their mathmatics degrees until fourth
> grade in Scotland.

Ah, maybe that's why they left---impatience with the educational
system. I've never believed great-great-granddad would have backed
down from a mere pointy stick.

This is the most fun I've had with Python strings since the Great
Objectification Debates began.

Cheerfully yours,
Michael

--
D. Michael McFarland <mcfa...@caber-eng.com>
Caber Engineering, Inc., Storrs, Connecticut

Tim Peters

unread,
Mar 3, 2001, 5:47:15 PM3/3/01
to pytho...@python.org
[Alex Martelli, with a wonderfully on-target explanation of why it's
sep.join(seq) and not seq.join(sep)]

Another reason could be that Guido is a dictator, and, like all dictators,
he's interested in killing off the various opposition groups that arise from
time to time. Now any dictator would be mad to believe that the opposition
will be cooperative enough to implement a method that lets him kill them off
by passing an instrument of execution:

future_haters.kill(knife)
curly_brace_lovers.kill(slow_strangulation)

This puts it outside his control! Much better for him if opposition groups
merely agree to enumerate themselves (and they probably need to have such a
protocol anyway, if for no other reason than to count their burgeoning
numbers). Then he can satisfy his blood lust via simply teaching his weapons
of mass destruction how to enumerate collections of people:

poison.kill(coalition_for_less_frequent_releases)
neutron_bomb.kill(coalition_for_more_frequent_releases)

Guido can deal with the enumeration mechanics just once then, in his
LethalWeapons base class.

Unfortunately, plain "kill" on its own doesn't make clear which is being
killed and which is the instrument of death. Ditto for plain "join".
Perhaps this whole brouhaha could have been avoided had we named
sep.join(seq) as sep.joining(seq) instead? Yuck. Anyone who suggests that
will be shot <wink>.

hoping-i'm-not-spilling-too-many-of-guido's-secrets-ly y'rs - tim


Amit Patel

unread,
Mar 4, 2001, 1:45:40 AM3/4/01
to

One thing that I *liked* about Python was that it had a split(a,b)
function instead of a method: a.split(b) or b.split(a).

When I see split(a,b), I think, "Oh, this isn't an inherent part of a
string-- *I* could write it, even though I didn't write the string
object."

When I see b.split(a), I think, "This is a basic part of a string, and
I *cannot* write it."


If I have a split-like function I'd like to write (perhaps
re.split, or some custom split function), then what I'll see is:

function style method style

string.split(a,b) b.split(a)
re.split(a,b) re.split(a,b)
mysplit(a,b) mysplit(a,b)

Note that with the function style, they're consistent -- MY function
is on equal footing with string.split. But with the new method style,
the split method on strings is elevated to a privileged position that
I cannot do for mysplit. So now I have inconsistent syntax.

So I will continue to use string.split in my code. I'll only use the
methods for things that are conceptually inherently tied to strings.
*Maybe* replace and index. But certainly not capitalize or center.
They feel like a user definable function that are in the string module
for convenience. At least in my mind, capitalize is NOT part of the
basic functionality of a string class.

- Amit
--
--
Amit J Patel, Computer Science Department, Stanford University
http://www-cs-students.stanford.edu/~amitp/

John W. Baxter

unread,
Mar 4, 2001, 2:12:26 PM3/4/01
to
In article <97rka...@news1.newsguy.com>,
"Alex Martelli" <ale...@yahoo.com> wrote:

> [Excellent exposition omitted.]

> So, since we want general polymorphism on the joiner
> object, but are quite content with polymorphism through
> the standard sequence interface on the sequence object,
> it is _just right_ that .join be a method on the joiner
> object (e.g., a string) and that it take the sequence of
> string to be joined as its argument.

OK, thanks. I'm convinced. For the first time. (Which won't
necessarily keep me from writing non-polymorphic things with the string
module, but it might make me *try* to remember.)

>
> I have not heard ANY _technical_ arguments opposed to
> this last time the discussion went around -- nothing but
> vague aesthetic, "it should be the other way", "I find it
> ugly" kind of complaints. Unless and until further notice,
> then, I class these together with the complaints of people
> who dislike 0-based indexing, on similar vague bases -- as
> 0-based indexing _works_ better than 1-based, then, for
> me, it is a superior choice.

Which doesn't mean I have to *like* zero-based indexing...only that I
have to use it. But then, *all* of the looping that was available in
the IBM 704 via the TXI, TXL, TXH family of instructions had fence-post
problems*, so I suppose I shouldn't be surprised.

--John (* if you build a straight fence with 10 posts 6 feet apart,
how long is the fence?)

Rainer Deyke

unread,
Mar 4, 2001, 4:05:27 PM3/4/01
to
"John W. Baxter" <jwb...@scandaroon.com> wrote in message
news:jwbnews-665CC3...@corp.supernews.com...

> OK, thanks. I'm convinced. For the first time. (Which won't
> necessarily keep me from writing non-polymorphic things with the string
> module, but it might make me *try* to remember.)

Actually, since the introduction of string methods, the string module has
started to behave polymorphically. Here's the implementation of
'string.join' as of 2.0:

def join(words, sep = ' '):
return sep.join(words)

String method make the string module more powerful.


--
Rainer Deyke (ro...@rainerdeyke.com)
Shareware computer games - http://rainerdeyke.com
"In ihren Reihen zu stehen heisst unter Feinden zu kaempfen" - Abigor


Alex Martelli

unread,
Mar 4, 2001, 4:42:28 PM3/4/01
to
"John W. Baxter" <jwb...@scandaroon.com> wrote in message
news:jwbnews-665CC3...@corp.supernews.com...
[snip]

> > it is _just right_ that .join be a method on the joiner
> > object (e.g., a string) and that it take the sequence of
> > string to be joined as its argument.
>
> OK, thanks. I'm convinced. For the first time. (Which won't

Glad my exposition helped someone.


> Which doesn't mean I have to *like* zero-based indexing...only that I

Of course not. I don't *like* broccoli just because it's demonstrably
good for me (actually, it's a vegetable I definitely dislike).


Alex

Delaney, Timothy

unread,
Mar 4, 2001, 8:45:06 PM3/4/01
to pytho...@python.org
> I have not heard ANY _technical_ arguments opposed to
> this last time the discussion went around -- nothing but
> vague aesthetic, "it should be the other way", "I find it
> ugly" kind of complaints. Unless and until further notice,
> then, I class these together with the complaints of people
> who dislike 0-based indexing, on similar vague bases -- as
> 0-based indexing _works_ better than 1-based, then, for
> me, it is a superior choice. Aesthetics is in the eye of the

I truly have no complaints with the technical merits of ''.join().

However, I have *severe* complaints with the aesthetics and consistency.
Quite simply, the way we look at things tends to be

"result" = "thing to be acted on to get the result" modified by "thing which
does the action"

This is consistently followed in the standard python libraries in almost all
cases ... but ''.join() is a glaring inconsistency. As a result, it seems
unintuitive and ugly.

This is why I prefer string.join(sequence, string). It is now syntactic
sugar for the above, and documented as such. However, it is *important*
syntactic sugar. It is known that the method is called polymorphically on
the second argument (a standard interface) but it feels that it is the first
argument which is the basis for the expression. This remains consistent with
the rest of the standard libraries.

OTOH, I suggest an alternative syntax ...

(sequence)join.''

There. Everyone should be happy with that ;)

Tim Delaney
Avaya Australia
+61 2 9352 9079

All recipient(s) of this email have permission to forward or reply to this
email, quoting this email in full or in part.

Greg Ewing

unread,
Mar 4, 2001, 9:15:44 PM3/4/01
to
Amit Patel wrote:
>
> But certainly not capitalize or center.
> They feel like a user definable function that are in the string module
> for convenience. At least in my mind, capitalize is NOT part of the
> basic functionality of a string class.

I second that. Capitalising, splitting, joining, etc. are
things that you do *to* strings, not things that strings
themselves do.

Another thing I'd like to mention is that, by keeping
as many things as possible *not* being methods, the modularity
of the core Python system is improved.

Suppose one day I wanted to make a cut-down version of
the Python interpreter for some specialised application
in which string processing wasn't going to be of much
importance. I might decide that I wanted to remove
most of the standard string-processing functions to
keep the size down.

If the string functions live in a separate module, I can
just recompile Python with that module disabled or replace
it with my own cut-down version.

But if they're methods of the string object, I have to
do surgery on one of the most basic built-in types, which
is a much hairier proposition.

--
Greg Ewing, Computer Science Dept, University of Canterbury,
Christchurch, New Zealand
To get my email address, please visit my web page:
http://www.cosc.canterbury.ac.nz/~greg

Greg Ewing

unread,
Mar 4, 2001, 9:06:43 PM3/4/01
to
Alex Martelli wrote:
>
> I have not heard ANY _technical_ arguments opposed to
> this last time the discussion went around -- nothing but
> vague aesthetic, "it should be the other way", "I find it
> ugly" kind of complaints.

While your arguments are _technically_ sound, we are yet
to be convinced that the benefits outweigh the drawbacks
of being forced to use what many find to be an obscure and
hard-to-follow syntax for all string joining.

The vast majority of string-joining operations in Python
code that I've seen and written haven't had any need for
polymorphism at all. On the rare occasions when I want a
polymorphic joiner[1], I'm quite willing to build the
necessary machinery and use whatever syntax is necessary.
But I don't want to pay the price of having to use that
syntax *every* time I join strings!

Footnotes:
[1] So rare, in fact, that so far I've *never* wanted one.
(Although I *have* written functions to do the join-the-
last-pair-with-something-different thing, I've never had
to choose between the two polymorphically.)

Paul Jackson

unread,
Mar 4, 2001, 9:46:24 PM3/4/01
to
Steve asks:

|> Do you mind if I quote you, with appropriate attribution?

Sure, that's fine. Thanks for the smile you
just put on my face.

Ype Kingma

unread,
Mar 5, 2001, 3:57:53 AM3/5/01
to

"Delaney, Timothy" wrote:
>
> > I have not heard ANY _technical_ arguments opposed to
> > this last time the discussion went around -- nothing but
> > vague aesthetic, "it should be the other way", "I find it
> > ugly" kind of complaints. Unless and until further notice,
> > then, I class these together with the complaints of people
> > who dislike 0-based indexing, on similar vague bases -- as
> > 0-based indexing _works_ better than 1-based, then, for
> > me, it is a superior choice. Aesthetics is in the eye of the
>
> I truly have no complaints with the technical merits of ''.join().
>
> However, I have *severe* complaints with the aesthetics and consistency.
> Quite simply, the way we look at things tends to be
>
> "result" = "thing to be acted on to get the result" modified by "thing which
> does the action"
>

Consider an alternate view:

"result" = "thing that will provide the result" modified by
"the action, ie. what thing should do"

> This is consistently followed in the standard python libraries in almost all
> cases ... but ''.join() is a glaring inconsistency. As a result, it seems
> unintuitive and ugly.

In the alternative view ''.join() reads like:

O yee empty string, please join this list of things.

Would you call that inconsistent?

The difference between the two views is
one of the differences between "procedural" and OO.

After getting used to OO I even found it aesthetic.

Regards,
Ype

-- email at xs4all.nl

Alex Martelli

unread,
Mar 5, 2001, 4:37:21 AM3/5/01
to
"Greg Ewing" <gr...@cosc.canterbury.ac.nz> wrote in message
news:3AA2F4B3...@cosc.canterbury.ac.nz...

> Alex Martelli wrote:
> >
> > I have not heard ANY _technical_ arguments opposed to
> > this last time the discussion went around -- nothing but
> > vague aesthetic, "it should be the other way", "I find it
> > ugly" kind of complaints.
>
> While your arguments are _technically_ sound, we are yet
> to be convinced that the benefits outweigh the drawbacks
> of being forced to use what many find to be an obscure and
> hard-to-follow syntax for all string joining.

Note that there is no 'forcing': once the right polymorphic
architecture has been chosen, one can still choose HIDE the
fact that polymorphism is happening behind a function call --
and, indeed, the string module supplies ready-made versions
of such calls (for backwards compatibility reasons, no doubt,
but, as a side effect, you can use it 'aesthetically'...!):

def replace(s, old, new, maxsplit=-1):
return s.replace(old, new, maxsplit)

and so on, and so forth. Personally, I prefer not to hide
such things (explicit better than implicit), but, you refined
aesthetes are being positively _pampered_ here -- a whole
module's worth of such syntax-sugar-providing functions...!


When you choose the right underlying architecture, the one
that best matches the actual needs, you MAY later decide to
'paper it over' with syntax-sugary superstructures if your
aesthetics so dictate -- since I am an engineer, I'm sure you
can guess what my attitude might be to such aesthetics, but
that's a different flamewar ("form follows function" crusaders,
this IS a call to arms!-).

The key point is that the actual *function* (the one which
I strongly opine 'form' should follow -- while acknowledging
the widespread human foible for 'dressing it up' in trompe
l'oeil 'prettiness':-) for joining IS: polymorphism on the
joiner object, access through standard sequence interface
for the sequence whose items are to be joined.

As long as that '_technically_ sound' architecture is the
underlying one (as, fortunately!, it is in Python 2), the
amount of actual damage you can do by covering it in your
chosen stucco and/or wallpaper is reasonably limited.

IF the underlying architecture did NOT reflect actual needs
(e.g., if the string.join function had to typeswitch on the
joiner-object to distinguish Unicode from single-byte --
and *every other* string module function had to similarly
typeswitch, rather than each being able to just delegate
to string-object's modules!), _then_ we'd be in deep doodoo.
But, fortunately, Python continued its tradition of pretty
good design indeed, introducing string methods in Python 2.


> The vast majority of string-joining operations in Python
> code that I've seen and written haven't had any need for
> polymorphism at all.

I guess you feel no need for Unicode -- what's the rest of
the world after all, we KNOW that all things that matter
only happen in countries where good ol' ASCII is quite
adequate for all of our string needs, right?


Alex

Alex Martelli

unread,
Mar 5, 2001, 4:57:03 AM3/5/01
to
"Delaney, Timothy" <tdel...@avaya.com> wrote in message
news:mailman.983756766...@python.org...
[snip]

> I truly have no complaints with the technical merits of ''.join().

Good.

> However, I have *severe* complaints with the aesthetics and consistency.
> Quite simply, the way we look at things tends to be
>
> "result" = "thing to be acted on to get the result" modified by "thing
which
> does the action"

This is bass-ackwards. The 'thing which does the action', i.e. the
object which will house the method code, is the one that NEEDS to come
first, because of how dispatching is coded in the Python language!


> This is consistently followed in the standard python libraries in almost
all

We seem to be using two VERY different languages/libraries - funny
that they're both named 'Python', innit. For example, in the Python
_I_ use, the re module defines objects (compiled regular expressions)
which are the 'things which do the action', and, sure enough, they
have methods which are passed the 'thing to be acted upon' as their
argument -- result = thing_doing_the_action.method(thing_acted_on).

Similarly, the pickle module defines objects (pickler objects) whose
methods are passed 'things to be acted upon' (e.g., a list to be
pickled can be passed to method dumps of the pickler, which returns
the result, a string).

And again, the urllib module defines object (URLopener objects)
whose methods are passed 'things to be acted upon' (e.g., open
is given a fullurl and optionally data) to return a result (here,
a file-like object).

And so on, and so forth. It's really very consistent -- it HAS
to be, because it's mostly dictated by technical considerations
of 'which object do we need full polymorphism on, which one is
best handled through a standard interface instead'.

> cases ... but ''.join() is a glaring inconsistency. As a result, it seems
> unintuitive and ugly.

What inconsistency?! It's exactly like the other cases -- the
object which does the action (here, a string-like object, who
works as a joiner) defines a method which is passed as argument
the object to be acted upon.


Alex

Jere Kahanpaa

unread,
Mar 5, 2001, 6:17:31 AM3/5/01
to
Sean 'Shaleh' Perry <sha...@valinux.com> wrote:
: return ";".join(["%s=%s" % (k, params[k]) for k in params.keys()])

: every day python seems to be moving closer to the line noise aspect of
: coding.

Agreed. Luckily anough I found Python in the clean, glorious days of 1.5.2
- the Unicode support in >1.6 was the *only* reason for me to upgrade as
XML processing in a multi-OS, multi-coding environment is really tricky
without Unicode.

Jere Kahanpää
--
Lord, make my words as sweet as honey, for one day I may have to eat them

Steve Holden

unread,
Mar 5, 2001, 11:28:57 AM3/5/01
to
"Delaney, Timothy" <tdel...@avaya.com> wrote in message
news:mailman.983756766...@python.org...
See the FAQ: I have added question 4.96. "Why is join() a string method when
I'm really joining the elements of a (list, tuple, sequence)?" which )for
some value of "summarises") summarises the discussions on this one. Please
feel free to shoot it down in flames. Just trying to keep the bandwidth
down.

done-my-good-deed-for-the-day-ly y'rs - steve

PS: Have a good time at the conference while I'm teaching Unix security in
New Mexico!


Russell E. Owen

unread,
Mar 5, 2001, 4:43:39 PM3/5/01
to
In article <97rka...@news1.newsguy.com>,
"Alex Martelli" <ale...@yahoo.com> wrote:

>"Russell E. Owen" <ow...@astrono.junkwashington.emu> wrote in message
>news:97p7iq$kk2$1...@nntp6.u.washington.edu...
> [snip]
>> However, I do agree that join is not intuitive. I believe the problem
>> (at least for the way I look at it) is that join should be a list
>> method, not a string method. I.e.:
>>
>> joined_string = ['a', 'b'].join(', ')
>>
>> makes a lot of sense to me. The current join string method does not.
>

> (long discussion about polymorphism omitted).

I'm afraid I don't understand where the polymorphism comes in, so I
cannot comment on that.

>...


>Say that I'm implementing a sequence-like object. Would
>having .join as a part of the set of methods I must write
>be an _advantage_ to me? As things stand now, to "be a
>sequence" I must just implement __getitem__ in the
>appropriate manner -- accepting an index from 0 to N-1,
>and raising IndexError for indices outside the range -- and
>maybe implement __length__ to return N. With this small
>amount of effort, I gain the ability to be used as sequence
>in any existing context -- from the for statement onwards.

I'm afraid we disagree here. Collections can all inherit from a parent
collection class, a perfectly reasonable requirement. You then define
the few methods that are required to make your own kind of collection.
The parent class should define things like join (which is, of course, a
very simple method).

-- Russell

Huaiyu Zhu

unread,
Mar 5, 2001, 6:47:38 PM3/5/01
to
It is all nice and well to say that sep.join(list) is good for polymorphism,
except that there are several practical annoyances:

1. The word join can be either transitive or nontransitive:
sep joins list.
list joins with sep.

Might sep.glue(join) be clearer? Well, compatibility with str.join?

2. Can we really join all kinds of lists?

>>> a = range(10)
>>> "".join(a)
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: sequence item 0: expected string, int found

3. What's the inverse of join? Is it split?

>>> b = [str(x) for x in a]
>>> c = "".join(b)
>>> c
'0123456789'
>>> d = "".split(c)
>>> d
['']

Oops! The other way round. Try again
>>> d = c.split("")
Traceback (most recent call last):
File "<stdin>", line 1, in ?
ValueError: empty separator

What? Oh, in this particular case, the inverse is
>>> d = list(c)
>>> d
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']

For other cases this is OK:
>>> c = ".".join(b)
>>> c
'0.1.2.3.4.5.6.7.8.9'
>>> d = c.split(".")
>>> d
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']

4. So can we just change the order of split? No. Consider

file.readlines()
file.read().splitlines()
file.read().split("\n")

More abstractly, when we split something, we have
whole - sep ==> components.
But when we join things together, we do it like
glue + components ==> whole,
rather then the "more natural"
components + glue => whole,
where "more natural" is defined as "most likely to be guessed by uninitiated
minds".

Of course, all these point do not detract from the fact that from
implementer's point of view, sep.join(list) is the most natural.

So what am I trying to say here? I'd say that there's not much point in
arguing, or even explaining which way is better. What would help is to
make things more symmetrical/smooth if possible.

Huaiyu

Erno Kuusela

unread,
Mar 5, 2001, 7:15:16 PM3/5/01
to
In article <97rka...@news1.newsguy.com>, "Alex Martelli"
<ale...@yahoo.com> writes:

| I have not heard ANY _technical_ arguments opposed to
| this last time the discussion went around -- nothing but
| vague aesthetic, "it should be the other way", "I find it
| ugly" kind of complaints.

what's wrong with vague aesthetic?-) if lots of people share it,
it's not to be dismissed so lightly.

-- erno

Skip Montanaro

unread,
Mar 5, 2001, 8:45:05 PM3/5/01
to Sean 'Shaleh' Perry, Mark Pilgrim, pytho...@python.org

Sean> Turning a string literal (";") suddenly into a string object and
Sean> then using its methods is not an easy read.

In Python, everything is an object. Thus, a string literal is a string
object - no "turning into" required. Just because it wasn't created by
instantiating a class doesn't make it any less an object.

The presence of join methods for strings and why that's where they landed
has been hashed and rehashed several times. Please check out FAQ 4.96 for
details.

Sean> ";" . join() # in perl, this means concat ";" with the result of
Sean> join()

Nobody ever claimed that Python was trying to be Perl... ;-) Just because
'";".join' is a fragment of valid expressions in both languages doesn't mean
they have to mean the same thing.

(In reality, I actually do my best to make my Perl code look as much like
Python to my Python-infected mind as I can.)

--
Skip Montanaro (sk...@mojam.com)
Support Mojam & Musi-Cal: http://www.musi-cal.com/sponsor.shtml
(847)971-7098

Steve Holden

unread,
Mar 5, 2001, 9:14:10 PM3/5/01
to
"Huaiyu Zhu" <hz...@users.sourceforge.net> wrote in message
news:slrn9a89d...@rocket.knowledgetrack.com...

> It is all nice and well to say that sep.join(list) is good for
polymorphism,
> except that there are several practical annoyances:
>
> 1. The word join can be either transitive or nontransitive:
> sep joins list.
> list joins with sep.
>
It can also be a noun. This is no more help than your assertion.

> Might sep.glue(join) be clearer? Well, compatibility with str.join?
>
> 2. Can we really join all kinds of lists?
>

No. I was somewhat startled to see that a UserList of integers could not be
given as an argument to join(). Relief of a kind arrived when I realised
that the same was true of lists themselves.

>>> import UserList
>>> reallist = [1, 2, 3, 4, 5]
>>> userlist = UserList.UserList(reallist)
>>> ":".join(reallist)
Traceback (innermost last):
File "<interactive input>", line 1, in ?


TypeError: sequence item 0: expected string, int found

>>> ":".join(userlist)
Traceback (innermost last):
File "<interactive input>", line 1, in ?


TypeError: sequence item 0: expected string, int found
>>>

It would seem reasonable to expect the join() method to try and coerce
things to lists, but maybe I'm not a reliable guide to what's reasonable.

[ ... ]


>
> 3. What's the inverse of join? Is it split?
>
> >>> b = [str(x) for x in a]
> >>> c = "".join(b)
> >>> c
> '0123456789'
> >>> d = "".split(c)
> >>> d
> ['']

Bzzt. This is along the lines of saying that since 0*x == o*y then x and y
must be equal. You really shouldn't argue from degenerate cases. The null
string is not a practical separator (for split()). Clearly it works for
join().

>
> Oops! The other way round. Try again
> >>> d = c.split("")
> Traceback (most recent call last):
> File "<stdin>", line 1, in ?
> ValueError: empty separator
>

Aha! So you''believe the interpreter, then?

> What? Oh, in this particular case, the inverse is
> >>> d = list(c)
> >>> d
> ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
>
> For other cases this is OK:
> >>> c = ".".join(b)
> >>> c
> '0.1.2.3.4.5.6.7.8.9'
> >>> d = c.split(".")
> >>> d
> ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
>

Quite.

> 4. So can we just change the order of split? No. Consider
>
> file.readlines()
> file.read().splitlines()
> file.read().split("\n")
>
> More abstractly, when we split something, we have
> whole - sep ==> components.
> But when we join things together, we do it like
> glue + components ==> whole,
> rather then the "more natural"
> components + glue => whole,
> where "more natural" is defined as "most likely to be guessed by
uninitiated
> minds".
>

You either have to understand the basis of a programming language's
operation, or copy other people's code in the hopes that it's well formed
and your use of it does not break it. "More natural" is an unprovable
assertion without usability testing, something which did feature in Python's
early development.

Nowadays, of course, everyone simply bitches like mad on c.l.py, and Guido
ignores our rantings and introduces execrescences such as "print >>" (don't
get me started :-)

> Of course, all these point do not detract from the fact that from
> implementer's point of view, sep.join(list) is the most natural.
>

There's the rub. We could all take the source and be our own implementer.
Few of us have the time and the stupidity^H^H^H^H^H^H^H^H^Hcourage.

> So what am I trying to say here? I'd say that there's not much point in
> arguing, or even explaining which way is better. What would help is to
> make things more symmetrical/smooth if possible.
>
> Huaiyu

Erm, use string.join() until it is taken away.

regards
Steve

Steve Holden

unread,
Mar 5, 2001, 9:24:14 PM3/5/01
to

"Skip Montanaro" <sk...@mojam.com> wrote in message
news:mailman.983843650...@python.org...

>
> Sean> Turning a string literal (";") suddenly into a string object and
> Sean> then using its methods is not an easy read.
>
> In Python, everything is an object. Thus, a string literal is a string
> object - no "turning into" required. Just because it wasn't created by
> instantiating a class doesn't make it any less an object.
>
> The presence of join methods for strings and why that's where they landed
> has been hashed and rehashed several times. Please check out FAQ 4.96 for
> details.
>
This isn't really fair, since I wrote 4.96 in response to this thread.

> Sean> ";" . join() # in perl, this means concat ";" with the result of
> Sean> join()
>
> Nobody ever claimed that Python was trying to be Perl... ;-) Just because
> '";".join' is a fragment of valid expressions in both languages doesn't
mean
> they have to mean the same thing.
>
> (In reality, I actually do my best to make my Perl code look as much like
> Python to my Python-infected mind as I can.)
>

just-getting-the-hang-of-this-time-machine-ly y'rs - steve

Greg Ewing

unread,
Mar 5, 2001, 11:01:56 PM3/5/01
to
Alex Martelli wrote:
>
> indeed, the string module supplies ready-made versions
> of such calls

For the time being, yes, but the intention has been
hinted at on python-dev to deprecate and eventually
remove the string module. That worries me.

> if the string.join function had to typeswitch on the
> joiner-object to distinguish Unicode from single-byte --

I don't get this business about avoiding type switches
by dispatching on the joiner, because you still have to
typeswitch on all the OTHER strings that you're joining.
So you save one (very fast C-level) typeswitch out of
quite a lot. Nowhere near a big enough gain to justify
anything, to my mind.

(And if ordinary strings and Unicode strings are ever
unified, this argument will go away completely.)

Frank Sergeant

unread,
Mar 6, 2001, 1:18:05 AM3/6/01
to

"Steve Holden" <sho...@holdenweb.com> wrote in message
news:Koco6.7518$1D5.2...@e420r-atl1.usenetserver.com...

> Ha! As an Englishman married to a Scot I'm not going to let you get
...

> Still, at least we can remind all that Scotland and England are different
> countries on c.l.py.

Yeah, sure, on c.l.py they are different countries, but that doesn't mean
they are different countries in real life.

> Lest people might think this is intended as criticism rather than
humo(u)r,
> I hasten to add that I lived in Scotland for three years before moving to
> the USA, and found the Scots to be extraordinarily warm and generous
people.

Yeah, sure, but what else can you say when you your wife is probably holding
one of those damn stocking daggers to your throat.


-- Frank
fr...@canyon-medical.com
bag pipes are weapons of war

Tim Hammerquist

unread,
Mar 6, 2001, 2:30:15 AM3/6/01
to
Skip Montanaro <sk...@mojam.com> wrote:
> (In reality, I actually do my best to make my Perl code look as much like
> Python to my Python-infected mind as I can.)

You are probably selling yourself short as far as Perl is concerned.
While I will never say that Perl is better than Python (nor the other
way 'round, for that matter), trying to use Pythonic syntax in Perl can
make the code run hundreds of times slower than taking advantage of Perl
idioms. If idioms are too much of an obstacle, maybe Python's a better
choice for you.

--
-Tim Hammerquist <ti...@cpan.org>

Big egos are big shields for lots of empty space.
-- Diana Black

Nathaniel Gray

unread,
Mar 6, 2001, 3:19:20 AM3/6/01
to
Huaiyu Zhu wrote:

> It is all nice and well to say that sep.join(list) is good for
> polymorphism, except that there are several practical annoyances:
>
> 1. The word join can be either transitive or nontransitive:
> sep joins list.
> list joins with sep.
>
> Might sep.glue(join) be clearer? Well, compatibility with str.join?

I actually always liked ":".joins(list), which you used above. It's much
harder to get backwards than "join". Alas, history has a way of trumping
clarity, and if the name changed from "join", to "joins" during the
transition to string methods, just as many people would be complaining
about the switch as now complain about sep.join(list).

-n8

--
_.~'^`~._.~'^`~._.~'^`~._.~'^`~._.~'^`~._
Nathaniel Gray
California Institute of Technology
Computation and Neural Systems
n8gray <at> caltech <dot> edu
_.~'^`~._.~'^`~._.~'^`~._.~'^`~._.~'^`~._

Alex Martelli

unread,
Mar 6, 2001, 4:02:08 AM3/6/01
to
"Greg Ewing" <gr...@cosc.canterbury.ac.nz> wrote in message
news:3AA46134...@cosc.canterbury.ac.nz...
[snip]

> > indeed, the string module supplies ready-made versions
> > of such calls
>
> For the time being, yes, but the intention has been
> hinted at on python-dev to deprecate and eventually
> remove the string module. That worries me.

It doesn't worry _me_, but I see where you're coming
from. Still, I would pass on the issue. The advantage
of having "one obvious way to do it" IS big, but so is
the problem of hurting the feelings of joiner.join-haters.
I'm glad I have no say on that particular decision!


> > if the string.join function had to typeswitch on the
> > joiner-object to distinguish Unicode from single-byte --
>
> I don't get this business about avoiding type switches
> by dispatching on the joiner, because you still have to
> typeswitch on all the OTHER strings that you're joining.

No! string_join (in stringobject.c) currently just _checks_
PyString_Check on the items -- if any item fails that, it
delegates to PyUnicode_Join (if PyUnicode_Check OK's that).

The latter is (IMHO) better-coded -- it uses the 'access
through standard interface' paradigm, i.e., it calls
PyUnicode_FromObject to let the items being joined have
a chance to make themselves into Unicode.

Unfortunately, there is (yet) no standard __unicode__
(or whatever) magic method, so the "make yourself into
Unicode" has to go through __str__.

Still, despite these signs of 'early design stages, still
needs to mature', the Unicode-joiner behavior is quite a
bit better already -- consider a typical case:

But absolutely *NOT*! You access the OTHER stuff through
standard interfaces. Take a typical case:

class stringable:
def __init__(self, x):
self.x = x
def __str__(self):
return str(self.x)

class singlebyte:
def __init__(self, N):
self.N = N
def __len__(self):
return self.N
def __getitem__(self, index):
if index>=self.N:
raise IndexError, index
return stringable(index)

Now, with something such as:

seq = singlebyte(7)

print '+'.join(seq)

print u'/'.join(seq)

the first print will raise an exception (as the joiner wants
the items to BE string-object already -- it does NOT use the
'access through standard interface' paradigm to give them a
chance to MAKE themselves into strings); the second one will
work just fine (as, IMHO, should the first one).

But anyway, the call to PyUnicode_FromObject is NOT a
typeswitch -- it's an "access through standard interface",
CONCEPTUALLY. There should be a slot in the type's method
table that gets directly probed to see if the object knows
how to make a Unicode object out of itself -- a fallback
to the _existing_ slot that may indicate a function whereby
the object knows how to make a singlebyte-string object out
of itself should also be included of course.

The implementation may not (yet) EXPLOIT the design's strengths,
but that is no basis by which to judge the DESIGN itself.


> So you save one (very fast C-level) typeswitch out of
> quite a lot. Nowhere near a big enough gain to justify
> anything, to my mind.

You gain a clean approach, which the implementation could
(and should) exploit to access the items in the sequence
through the _appropriate_ standard interface (also, there
should be no mandate on the sequence to define 'length',
I think, just as there isn't for a for-loop -- but I do
understand there are tradeoffs here). Some gain today,
and an excellent architectural/design basis for further
gains tomorrow when the implementation catches up with
the design's potential for excellence.

You further gain, as I have already shown, the advantage
of polymorphism when you want a joiner object to do
something special -- at NO COST, as usual for uses of
polymorphism -- even code you wrote months ago, with no
idea that 'special joining' would be needed, will get
this extra flexibility if it accepts the joiner object
to use as an argument and just calls its join method.

There are NO technical costs associated with these
advantages. Your purely-aesthetical, technically
unmotivated dislike for joiner.join, on a strictly
syntax-sugar level, is clearly just about balanced
by the just-as-aesthetical, just-as-arbitrary liking
it by others. Only technical advantages and costs
can be fairly put on the balance -- and, here, we
have ZERO technical costs to weigh against clear
technical advantages; it does not matter, therefore,
if one judges those technical advantages large (as
I do) or small (as others might) -- they're >0, and
so the joiner.join approach is a 100% winner on
technical grounds (the only rationally debatable ones).

If a single approach should be allowed, then it would
therefore HAVE to be the one presenting technical
pluses, rather than the one presenting NO pluses
on that level.

Note that I've seen NO arguments AT ALL for having
.join be a method on SEQUENCE object (rather than
on the joiner), despite this being often mentioned
on an irrational-purely-aesthetical basis. Any
taker...?


> (And if ordinary strings and Unicode strings are ever
> unified, this argument will go away completely.)

If it should ever happen that NO polymorphism can
ever appear on the joiner object, then there would
be no technical advantage in allowing polymorphic
behavior on it -- a tautology. In fact, special kinds
of quasi-string objects might still emerge in the same
kind of far-away-hypothetical-future frame as the
one in which single-byte/Unicode distinctions can
disappear, and then, again, the polymorphic aspects
of joiner.join will show to advantage (as they always
will for any special-joining needs).


Alex

Alex Martelli

unread,
Mar 6, 2001, 4:16:55 AM3/6/01
to
"Steve Holden" <sho...@holdenweb.com> wrote in message
news:DNXo6.24266$1D5.9...@e420r-atl1.usenetserver.com...
[snip]

> > 2. Can we really join all kinds of lists?
> >
> No. I was somewhat startled to see that a UserList of integers could not
be
> given as an argument to join(). Relief of a kind arrived when I realised
> that the same was true of lists themselves.
[snip]

> It would seem reasonable to expect the join() method to try and coerce
> things to lists, but maybe I'm not a reliable guide to what's reasonable.

It's not an issue of lists vs other stuff -- .join accepts as
its argument any sequence which defines a length, which is
reasonable (although it might be nice to remove that need for
the length being defined -- the sequence-length is only used
to control a for-loop, after all, so the test-for-IndexError
might suffice; but I guess unbounded-sequences might prove to
be a problem here).

The key issue, anyway, is with the _items_ in the sequence,
rather than with the sequence itself. The join method on
a single-byte string wants each item to *BE* a single-byte
string -- peculiar behavior follows if it isn't, consider:

class Sequence:
def __init__(self, N, value):
self.N = N
self.value = value


def __len__(self):
return self.N
def __getitem__(self, index):
if index>=self.N:
raise IndexError, index

return self.value

>>> sb=Sequence(3,'aa')
>>> 'x'.join(sb)
'aaxaaxaa'
>>> u'y'.join(sb)
u'aayaayaa'
>>> uc=Sequence(3,u'bbb')
>>> u'z'.join(uc)
u'bbbzbbbzbbb'
>>> 't'.join(uc)


Traceback (most recent call last):
File "<stdin>", line 1, in ?

TypeError: coercing to Unicode: need string or buffer, tuple found

and a Control-Z now crashes/hangs the Python interpreter (2.0, on
Win32). OK, some kind of ugly bug in 2.0 (gotta get 2.1b1 and
check if the bug is still there...!!!).


Alex

Alex Martelli

unread,
Mar 6, 2001, 4:20:06 AM3/6/01
to
"Erno Kuusela" <erno...@erno.iki.fi> wrote in message
news:kuu257k...@lasipalatsi.fi...

Lots of people share the 'vague aesthetic' of desiring
to use braces instead of whitespace to delimit blocks
of statements, for example.

Python dismisses that lightly, and that is definitely
a part of what makes it such a wonderful language.


Alex

Alex Martelli

unread,
Mar 6, 2001, 4:25:28 AM3/6/01
to
"Huaiyu Zhu" <hz...@users.sourceforge.net> wrote in message
news:slrn9a89d...@rocket.knowledgetrack.com...
> It is all nice and well to say that sep.join(list) is good for
polymorphism,
> except that there are several practical annoyances:
>
> 1. The word join can be either transitive or nontransitive:
> sep joins list.
> list joins with sep.

The first way one tries to parse a method-name is as the
imperative form of some verb -- transitive if it takes
arguments, intransitive if it's without arguments. I am
not a native speaker of English, but I strongly suspect
this generalizes to those who are.

> 2. Can we really join all kinds of lists?

We can join any kind of sequence which defines a length,
with some irregularities and bugs (regarding, not the
sequence itself, but the types of its _items_) depending
on the kind of joiner object: when the joiner object is
a single-byte string, the items must also be (unicode
object items are supposed to be accepted too, but there
is a bug in Python 2.0 which interferes sometimes); when
the joiner object is a Unicode string, the items may be
any object that defines a way to make it into Unicode
(in Python 2, e.g., an instance object with a __str__
method).

I hope some of these irregularities go away in 2.1...:-).


Alex

Alex Martelli

unread,
Mar 6, 2001, 5:02:12 AM3/6/01
to
"Russell E. Owen" <ow...@astrono.junkwashington.emu> wrote in message
news:9811a8$k5k$1...@nntp6.u.washington.edu...
[snip]

> > (long discussion about polymorphism omitted).
>
> I'm afraid I don't understand where the polymorphism comes in, so I
> cannot comment on that.

If you don't understand polymorphism in general, then I don't
see how you can comment on any OO design.

If you're instead saying that you don't see where polymorphism
can help for this _specific_ case, what's so mysterious about
the specific example I gave? Here it is again, more or less,
with a bit more fluff around it:

good_things = (
'money', 'bridge', 'champagne',
'wine', 'women', 'song'
)
def joined_niceties(things, joiner=', '):
nice_things = [thing for thing in things if thing in good_things]
return joiner.join(nice_things)

>>> words = 'programming money bridge spam champagne'.split()
>>> print joined_niceties(words)
money, bridge, champagne
>>> print joined_niceties(words, ' - ')
money - bridge - champagne

class MixedJoiner:
def __init__(self, joiner1, joiner2):
self.joiner1 = joiner1
self.joiner2 = joiner2
def join(self, sequence):
return joiner2.join((
joiner1.join(sequence[:-1]),
sequence[-1]))

>>> print joined_niceties(words, MixedJoiner(', ', ' and '))
money, bridge and champagne


We have some code (here, function joined_niceties) that somehow
prepares or obtains a sequence (here, nice_things, prepared by
selection from an argument to the function via membership in a
global-data list) and must return the string obtained by joining
said sequence with an arbitrary joiner (here, argument joiner,
defaulting to ", " -- comma-then-blank, often a decent way to
join words into a string).

Thanks to the fully general polymorphism that joiner.join affords,
we can then use a *special* joiner-object to do fancy joining.

This imposes NO technical cost whatsoever on the code that does
the joining (here, function joined_niceties) -- indeed, such code
can have been written months ago, before we even had an inkling
that the joiner-object would ever be other than a string. This is
the common magic of polymorphism -- code can be closed to changes
yet open for modification (here, this applies to joined_niceties --
we need not change it to obtain fancy-joining, it all comes from
free thanks to the polymorphism on the joiner-object!).

So, we code a suitable joiner-object -- here, one that conjoins
two other joiners, using one for all but the last join, the other
for the last join only. This use, of course, easily generalizes:

>>> commas_then_and = MixedJoiner(", ", " and ")
>>> commas_and_even = MixedJoiner(commas_then_and, " or even ")
>>> words = 'women money work bridge beans wine champagne spam'.split()
>>> print joined_niceties(words, commas_and_even)
women, money, bridge and wine or even champagne

without any further complexity, all through the magic of general
polymorphism. Polymorphism is what's _truly_ great about object
oriented programming (and can also be obtained via some other
paradigms, such as generic-programming, with different costs and
advantages in various programming languages) -- getting the RIGHT
behaviour for a given specific case, from GENERAL client-code that
just appropriately asks one or more objects to "do the right
thing for purpose X" (by calling the appropriate methods with
the right arguments).


> >Say that I'm implementing a sequence-like object. Would
> >having .join as a part of the set of methods I must write
> >be an _advantage_ to me? As things stand now, to "be a

[snip]


> I'm afraid we disagree here. Collections can all inherit from a parent
> collection class, a perfectly reasonable requirement. You then define
> the few methods that are required to make your own kind of collection.
> The parent class should define things like join (which is, of course, a
> very simple method).

So, there is NO advantage in having .join as a part of my
set of methods -- there IS the cost that I have to inherit
from some base-class, which may be 'perfectly reasonable'
(or not) but still IS a cost I have to pay, compared with
the present situation where no inheritance is REQUIRED.

For example, if I want to implement a sequence-like object
in a C-coded extension to Python (hardly an unreasonable
need!), then .join, and any other convenience methods that
may be required to "be a sequence", are PURE OVERHEAD. It
makes my programming task harder; and, *where are the
benefits* corresponding to this cost?! I have seen no
technical benefits claimed yet for making .join a method
of the sequence-like object -- in what use cases would the
resulting polymorphism be a functional _benefit_, to have
the sequence behave differently when it is to be joined
rather than (say) when it's to be written to a file-like
object (via the .writelines method of the f-l obj) or
otherwise iterated upon?

There's also some issue here with 'Collection' (a more
general concept than 'Sequence' -- why should we constrain
ALL collections to be sequenceable?!), but let's let that
pass for the moment.

Mixin base-classes are a good way to add convenience
methods to my own objects through the design pattern
'template' (as named by the Gof4 -- no relation to such
things as C++ templates, etc). We have no disagreement
on THAT -- *IF* a method (that is generally suitable for
implementation via 'template' dp) is appropriate, then
mixin inheritance is a good implementation approach.
We DO have disagreement that .join is at all appropriate
as a method of sequences -- let alone more general
collections!!!

Furthermore: PLEASE show us how you would implement
the 'very simple method' that you claim the base
class .join would be. Be sure, at the very least, to
handle both joiners that are single-byte strings, and
ones that are unicode-strings, assuming of course they
have no 'join' methods themselves. It is also very
important that your .join's performance characteristics
be *reasonable* -- O(N) in time and space, where N
is the length of the resulting string; O(N*N) would
be a major disaster, as I hope you'll agree (a design
that forces an O(N) algorithm to become O(N*N) IS an
intrinsic disaster -- no aesthetic justification can
make up for that...:-).


Alex

Paul Moore

unread,
Mar 6, 2001, 6:42:08 AM3/6/01
to
On Tue, 6 Mar 2001 10:16:55 +0100 , "Alex Martelli"
<ale...@yahoo.com> wrote:
>>>> uc=Sequence(3,u'bbb')
>>>> u'z'.join(uc)
>u'bbbzbbbzbbb'
>>>> 't'.join(uc)
>Traceback (most recent call last):
> File "<stdin>", line 1, in ?
>TypeError: coercing to Unicode: need string or buffer, tuple found
>
>and a Control-Z now crashes/hangs the Python interpreter (2.0, on
>Win32). OK, some kind of ugly bug in 2.0 (gotta get 2.1b1 and
>check if the bug is still there...!!!).

Yes, this is fixed in 2.1b1.

Paul.

Skip Montanaro

unread,
Mar 6, 2001, 7:21:00 AM3/6/01
to Steve Holden, pytho...@python.org

>> The presence of join methods for strings and why that's where they
>> landed has been hashed and rehashed several times. Please check out
>> FAQ 4.96 for details.

Steve> This isn't really fair, since I wrote 4.96 in response to this
Steve> thread.

My apologies. I was out of town for a few days. Upon seeing this thread I
decided I would create a FAQ entry, but an initial search turned up 4.96.
In my rush to wave it in front of people I failed to notice the date on it.

Skip

Erno Kuusela

unread,
Mar 6, 2001, 8:09:32 AM3/6/01
to
In article <982a4...@news1.newsguy.com>, "Alex Martelli"
<ale...@yahoo.com> writes:

| "Erno Kuusela" <erno...@erno.iki.fi> wrote in message

|| what's wrong with vague aesthetic?-) if lots of people share it,


|| it's not to be dismissed so lightly.

| Lots of people share the 'vague aesthetic' of desiring
| to use braces instead of whitespace to delimit blocks
| of statements, for example.

| Python dismisses that lightly, and that is definitely
| a part of what makes it such a wonderful language.

it could also be argued that python uses whitespace instead
of braces because of vague aesthetic shared by lots of people. :)

-- erno

Steve Holden

unread,
Mar 6, 2001, 9:07:09 AM3/6/01
to
"Erno Kuusela" <erno...@erno.iki.fi> wrote in message
news:kuofvfj...@lasipalatsi.fi...
Well it could be argued, but you could also look at the usability data which
(I understand) was the basis of this choice when Python was originally
designed.

not-going-back-to-braces-now-ly y'rs - steve

Erno Kuusela

unread,
Mar 6, 2001, 9:37:28 AM3/6/01
to
In article <1e6p6.27206$1D5.1...@e420r-atl1.usenetserver.com>,
"Steve Holden" <sho...@holdenweb.com> writes:

| "Erno Kuusela" <erno...@erno.iki.fi> wrote in message

| news:kuofvfj...@lasipalatsi.fi...

|| it could also be argued that python uses whitespace instead
|| of braces because of vague aesthetic shared by lots of people. :)

| Well it could be argued, but you could also look at the usability data which
| (I understand) was the basis of this choice when Python was originally
| designed.

aha! clearly, we need a usability study on string methods.

-- erno

Alex Martelli

unread,
Mar 6, 2001, 9:15:51 AM3/6/01
to
"Erno Kuusela" <erno...@erno.iki.fi> wrote in message
news:kuofvfj...@lasipalatsi.fi...

If it's "shared by lots of people", how come Python, Haskell and
Occam -- languages which, between them, may account for _maybe_
10% of the world's programmers (much fewer, I suspect) -- are
the only ones to support such whitespace-for-grouping usage...?

Fortunately, Python's choices are not determined by majority
voting, but by our benevolent dictator -- whose good sense of
design, despite the lapse of print>>, is clearly of the highest
order. I consider the choice of making .join a method of the
joiner object one more example of that excellent design-sense.


Alex

Mike C. Fletcher

unread,
Mar 6, 2001, 9:46:53 AM3/6/01
to pytho...@python.org
Here's a professional aesthetic's take:

mystring.join( )

This is a perfectly normal and good-looking construct. It seems pythonic
and beautiful, object orientation is part of Python, and this works nicely.

"'".join( )
";".join( )
".".join( )
"!".join( )
",".join( )

All look like executable line noise. That is, the literal string's syntax
makes the use of dotted attributes on such a string look jarring and
off-putting. You almost expect some weird function to jump out of this
syntax. It looks very Ruby/Perl-esque.

Note particularly the amount of space between the " character and the .
character. Typographically, " characters serve to set the enclosing data
off from the outer context, and that's the opposite of what you're trying to
do with dot notation. Dot notation normally looks natural because almost
every character that gets used right before the . comes fairly close to the
. (even characters such as r ). Also note: in the common cases of
single-character joins, there's no significant visual weight difference
between what's inside and outside the quotes). Consider what happens when
you alter the proportions of space and the size of the connector...

"."__join( )
"."-->join( )
"."..join( )
" "__join( )

You should find those slightly easier on the eyes (except possibly the " "
one) because the entire "." entity can be understood as a single graphic
with a connector to "join".

That said, I don't think we'll get this particular wart out of the language,
so we'll have to deal with the flaw in the way artists have through the
ages, enhance it and accent it so people start to think it's a beauty mark.
Mike


Michael Hudson

unread,
Mar 6, 2001, 10:24:10 AM3/6/01
to
Erno Kuusela <erno...@erno.iki.fi> writes:

Some people don't have a problem with, or even quite like, ''.join,
too.

They tend to be quieter, though.

Cheers,
M.

--
For their next act, they'll no doubt be buying a firewall running
under NT, which makes about as much sense as building a prison out
of meringue. -- -:Tanuki:-
-- http://home.xnet.com/~raven/Sysadmin/ASR.Quotes.html

Clarence Gardner

unread,
Mar 6, 2001, 10:53:37 AM3/6/01
to
On Tue, 06 Mar 2001, Mike C. Fletcher wrote:
>Here's a professional aesthetic's take:
>
> mystring.join( )
>
>This is a perfectly normal and good-looking construct. It seems pythonic
>and beautiful, object orientation is part of Python, and this works nicely.
>
> "'".join( )
> ";".join( )
> ".".join( )
> "!".join( )
> ",".join( )
>
>All look like executable line noise. That is, the literal string's syntax
>makes the use of dotted attributes on such a string look jarring and
>off-putting.
<snip>

>That said, I don't think we'll get this particular wart out of the language,
>so we'll have to deal with the flaw in the way artists have through the
>ages, enhance it and accent it so people start to think it's a beauty mark.

comma.join()
period.join()
bang.join()
etc.


John W. Baxter

unread,
Mar 6, 2001, 12:39:14 PM3/6/01
to
With luck and good will, we ought not have so many of this sort of
discussion after the fact in the future.

We now have the PEP process...and the discussion of the PEP is the right
place for alarms to be raised, both technical ("that fails when...") and
otherwise ("I'd rather see this than that.").

Previously, much of the community* didn't see the developer discussions,
so the changes tended to spring upon us already decided and implemented.
[* I'm overweight enough that even if I'm alone in that, it's still
"much of the community".]

We'll see in the next couple of rounds (post 2.1) how well the above
works out it practice. Even in Python, the later in the product cycle a
change is made, the more it costs.

--John

--
John W. Baxter Port Ludlow, WA USA jwb...@scandaroon.com

Donn Cave

unread,
Mar 6, 2001, 2:36:38 PM3/6/01
to
Quoth "John W. Baxter" <jwb...@scandaroon.com>:

| With luck and good will, we ought not have so many of this sort of
| discussion after the fact in the future.
|
| We now have the PEP process...and the discussion of the PEP is the right
| place for alarms to be raised, both technical ("that fails when...") and
| otherwise ("I'd rather see this than that.").

Actually I think that may be representative of a misunderstanding about
what's going on here. I don't think I have seen a many posts in this
branch of threads that took the position, in so many words, that the
features in question shouldn't have been implemented in Python. The
ones that have, have taken kind of surprising angles on it, like the
idea that string functions might profitably be omitted from a special
purpose small subset interpreter. There have been plenty of criticism,
but speaking for myself, if people see a categoric rejection of the
feature there, they're reading something into my words that wasn't in
my head. That is an easy mistake to make, it's just simplistic.

I would expect that if these same people were herded into a room and
subjected to a PEP discussion, they would neither raise technical
alarm nor suggest better alternatives, and not for lack of imagination
but simply because these features aren't that in kind of trouble.
They more or less make sense, and they're here for more or less valid
reasons. Yet afterwards, you will read "this is line noise." Not
because the PEP process failed, it just doesn't address the question
of how to program in Python. We ought to recognize this landscape
pretty well, because we have seen the Perlites walking through it all
along. They're acutely conscious of the difference between what the
language can be and what people make of it. As Python gets richer,
the same forces come to bear on it. I don't know if we have a choice
to not get richer, it's probably a categorical imperative that is as
silly to resist as the ensuing entropy. But we can and do occasionally
turn away from a few features that come along, they don't all get into
Python and we always have the choice of how to write our own software.
We don't have a huge problem yet, but it's good to face up to what
little problems we do have.

The threads can get pretty tedious, and it sure is not obvious that
it's a good way to solve any problem. There is an awful lot of talking
at cross purposes, particularly if you accept my premise that none of
us want to actually repeal the features in question. But I think there's
some good in it anyway. Only this morning, when I thought everything
must have been said several times over, someone made a point about
methods and literals, one of those insights that are so obvious in
retrospect I'm kind of embarrassed to admit, which is the sign of a
good point. I don't want to suppress that kind of thing, because it
helps me think about what I can do to write well.

Donn Cave, do...@u.washington.edu

Carel Fellinger

unread,
Mar 6, 2001, 7:06:13 PM3/6/01
to

once Alex Martelli wrote:
...
> that's a different flamewar ("form follows function" crusaders,
> this IS a call to arms!-).

so you wanna fight he,

and else were he wrote
... bunch of disgustingly true ramblings on polymorphisme snipped


and now he comes with
> class MixedJoiner:
...


> Thanks to the fully general polymorphism that joiner.join affords,
> we can then use a *special* joiner-object to do fancy joining.

So let's reverse things:

>>> class MixedSplitter:
... def __init__(self, splitter1, splitter2):
... self.splitter1, self.splitter2 = splitter1, splitter2
... def split(self, sequence):
... s = self.splitter1(sequence)
... return s[:-1] + self.splitter(s[-1])
...
>>> ms = MixedSplitter(', ', ' and ')
>>> ms.split('1, 2, 3 and 4')
some nasty errormessage snipped


This won't work with Python2.
Ofcourse we could ammend MixedSplitter's split method like:

>>> def split(self, sequence):
... s = sequence.split(self.splitter1)
... return s[:-1] + s[-1].split(self.splitter2)
...
>>> MixedSplitter.split = split
>>> ms.split('1, 2, 3 and 4')
['1', '2', '3', '4']

But the real evil is that no code out there will allow us to easily
use the polimorphic nature of this splitter.


The moral being that we shouldn't argue about the uglines joiner.join
but of the lack of a tru polymorphic splitter.split!
--
groetjes, carel

Steve Holden

unread,
Mar 6, 2001, 7:35:53 PM3/6/01
to
"Mike C. Fletcher" <mcfl...@home.com> wrote in message
news:mailman.983890030...@python.org...

> Here's a professional aesthetic's take:
>
A professional would call themself an aesthete :-)

> mystring.join( )
>
> This is a perfectly normal and good-looking construct. It seems pythonic
> and beautiful, object orientation is part of Python, and this works
nicely.
>

Agreed.

> "'".join( )
> ";".join( )
> ".".join( )
> "!".join( )
> ",".join( )
>
> All look like executable line noise. That is, the literal string's syntax
> makes the use of dotted attributes on such a string look jarring and
> off-putting. You almost expect some weird function to jump out of this
> syntax. It looks very Ruby/Perl-esque.
>

Just the same, a beginner can read the code as "some string's method is
applied to whatever argument is passed" just by knowing the syntax.

> Note particularly the amount of space between the " character and the .
> character. Typographically, " characters serve to set the enclosing data
> off from the outer context, and that's the opposite of what you're trying
to
> do with dot notation. Dot notation normally looks natural because almost
> every character that gets used right before the . comes fairly close to
the
> . (even characters such as r ). Also note: in the common cases of
> single-character joins, there's no significant visual weight difference
> between what's inside and outside the quotes). Consider what happens when
> you alter the proportions of space and the size of the connector...
>

Well, if you like white space Python should be the perfect language for you!

> "."__join( )
> "."-->join( )
> "."..join( )
> " "__join( )
>
> You should find those slightly easier on the eyes (except possibly the " "
> one) because the entire "." entity can be understood as a single graphic
> with a connector to "join".
>

What about the currently syntactically-acceptable

>>> ", " . join(["big", "fat", "joint"])
'big, fat, joint'
>>>

Remember that technically the dot is an operator. Personally I find the
extra whitespace intrusive, but that is a matter of style and taste. Any
better for you?

> That said, I don't think we'll get this particular wart out of the
language,
> so we'll have to deal with the flaw in the way artists have through the
> ages, enhance it and accent it so people start to think it's a beauty
mark.
>

Not a wart, but a consistent application of object-oriented principles.
Sorry. I too wish the world looked more beautiful (to you).

but-if-wishes-were-horses-then-bill-gates-would-have-hoofmarks-in-his-ass-ly
y'rs - steve

Greg Ewing

unread,
Mar 6, 2001, 8:16:00 PM3/6/01
to
Alex Martelli wrote:
>
> No! string_join (in stringobject.c) currently just _checks_
> PyString_Check on the items -- if any item fails that, it
> delegates to PyUnicode_Join (if PyUnicode_Check OK's that).

And that's somehow not a typeswitch? If it's a regular
string do this... if it's a Unicode string do that...
smells like a typeswitch to me...

You seemed to be arguing that dispatching on the joiner
somehow resulted in an efficiency gain by going straight
to the right code for the kind of strings being joined,
and I was pointing out that that's not the case. But
maybe I misunderstood what you were saying.

> You gain a clean approach, which the implementation could
> (and should) exploit to access the items in the sequence
> through the _appropriate_ standard interface

It's only clean according to one measure of cleanness.
It could be considered cleaner to treat all the arguments
uniformly, and access them *all* through a standard
interface.

> There are NO technical costs associated with these
> advantages.

I disagree. I've mentioned one already -- it bloats the
string object, and makes the Python core larger and
less modular.

> Only technical advantages and costs
> can be fairly put on the balance

I disagree with that, too. I think it's quite possible
and appropriate for a small technical advantage to be
outweighed by a larger aesthetic one. For example, there
are technical advantages to braces instead of indentation:
the scanner is easier to implement, it's easier to write
programs which generate code, and there's no chance of
space-tab confusion. On the indentation side, there's the
advantage that indentation and block structure always
agree. If you're counting technical advantages, that's
one in favour of indentation and three against. But I
doubt Guido would switch on that basis.

> Note that I've seen NO arguments AT ALL for having

> .join be a method on SEQUENCE object ... despite this

> being often mentioned on an irrational-purely-aesthetical
> basis.

I don't think the basis is irrational at all. It
seems to me that there are two quite distinct possible
reasons for deciding to make something a method of a
particular object.

One is to get polymorphism on that object. The other
is because the object makes sense as the direct object
(in the English grammar sense) of the operation, so
that you can naturally read x.verb(y) as "verb x
with y" or "verb x using y".

When these two considerations pull in the same
direction, all is well. And with most of the string
methods they do, but in the case of join, they don't.
There are good reasons for not making it a method of
the sequence, but when it is made a method of the
joiner, the resulting expression sounds backwards[1].

So we are faced with two alternatives, neither
of which are entirely good. In such cases, my
preference is not to choose either alternative --
i.e. make join a function, not a method.

Footnotes:
[1] In English, anyway. Maybe it doesn't sound backwards
in Dutch. Hmmm... is THAT why Guido accepted it?

Mike C. Fletcher

unread,
Mar 6, 2001, 8:31:51 PM3/6/01
to Python List (E-mail)
Aesthetes are a different kind of professional, I'm a design theorist, those
are art wh#$3s ;) . Sorry, I dislike the connotations of "aesthete" (too
turn of the last century eclecticism for me), so I use aesthetic (which, I
feel, has a much nicer resonance with "ascetic", which is closer to my sense
of beauty).

I have no problem with the semantics of the string having methods. I asked
for lists and tuples to have a consistent and complete set of methods 2 or 3
years ago if I'm recalling correctly. Healing the class/type split is
something I would like to live to see (if the PSU doesn't get me first).

I'll have to give that Python thing a try. Can you recommend any good books
for someone who's been stuck in a backwater language for the last 6 years?
Isn't that Python thing slow though? I heard they don't even have static
type declarations and they don't support polymorphic function signature
dispatches.

"," . join( ) doesn't help much, as there's no graphical connection drawn
between the two items, so you lose the correspondence of the . character to
"member of" (i.e. the glyph no longer represents the concept, but must be
interpreted at a semantic level to make the construct clear).

As I mentioned, I don't expect this to change, just wanted to point out that
there is a legitimate complaint from an aesthetic standpoint.

Enjoy,
Mike


-----Original Message-----
From: Steve Holden [mailto:sho...@holdenweb.com]
Sent: Tuesday, March 06, 2001 7:36 PM
To: pytho...@python.org
Subject: Re: I come to praise .join, not to bury it...
...
A professional would call themself an aesthete :-)
...
Just the same, a beginner can read the code as "some string's method is
applied to whatever argument is passed" just by knowing the syntax.
...
Well, if you like white space Python should be the perfect language for you!

...


What about the currently syntactically-acceptable

>>> ", " . join(["big", "fat", "joint"])
'big, fat, joint'
>>>

Remember that technically the dot is an operator. Personally I find the
extra whitespace intrusive, but that is a matter of style and taste. Any
better for you?

...


Not a wart, but a consistent application of object-oriented principles.
Sorry. I too wish the world looked more beautiful (to you).

...


Alex Martelli

unread,
Mar 7, 2001, 4:01:01 AM3/7/01
to
"Mike C. Fletcher" <mcfl...@home.com> wrote in message
news:mailman.983928669...@python.org...

> Aesthetes are a different kind of professional, I'm a design theorist,
those
> are art wh#$3s ;) . Sorry, I dislike the connotations of "aesthete" (too
> turn of the last century eclecticism for me), so I use aesthetic (which, I
> feel, has a much nicer resonance with "ascetic", which is closer to my
sense
> of beauty).

Funny enough, that is also very close to what _I_, a mere engineer,
perceive as 'beauty': lack of decoration, match between form and
function, spareness, simplicity. As another 'engineer' put it,
perfection is reached, not when there's nothing more left to add,
but when there's nothing more left to be taken away (well, _almost_
an engineer -- he failed the examinations for his certificate --
although, as a pioneer of flight, he worked basically in the field
of engineering afterwards; maybe the epsilon of engineering he
lacked was the 'but practicality trumps purity' lithmus test...;-).


> I have no problem with the semantics of the string having methods. I
asked
> for lists and tuples to have a consistent and complete set of methods 2 or
3
> years ago if I'm recalling correctly. Healing the class/type split is
> something I would like to live to see (if the PSU doesn't get me first).

Indeed, such developments have contributed, and/or will/would
contribute, to the deep underlying beauty of the language in
the above-mentioned reference terms.


> I'll have to give that Python thing a try. Can you recommend any good
books
> for someone who's been stuck in a backwater language for the last 6 years?

My favourite books for Python beginners are:
"Learning Python", Mark Lutz & David Ascher, O'Reilly, 1-56592-464-9
"The Quick Python Book", Daryl Harms & Kenneth McDonald , Manning,
1-88477-774-0

They're not up-to-date to Python 2.0, I believe, but either will give
a good grounding on the fundamentals, and learning the 2.0/2.1 changes
on top of that is no biggie. Lutz & Ascher cover slowly, thoroughly,
and in depth, the language itself and the key parts of its libraries;
Harms & McDonald move faster, and cover (not quite as deeply) a wider
selection of topics. Choice between them is a matter of taste.

> Isn't that Python thing slow though? I heard they don't even have static
> type declarations and they don't support polymorphic function signature
> dispatches.

Python's polymorphism is by-method, not by 'function signature', but that's
hardly an issue of speed. As for speed, I find Python perfectly adequate
for my needs, with the proviso that some low-level performance bottlenecks
may have to be coded as extension modules -- of course, lots of such high
performance 'extensions' already exist, so, depending on your needs, you
may need no non-Python coding (e.g., for numeric operation on large arrays
and matrices, the Numeric extensions may already provide what you need).


> "," . join( ) doesn't help much, as there's no graphical connection drawn
> between the two items, so you lose the correspondence of the . character
to
> "member of" (i.e. the glyph no longer represents the concept, but must be
> interpreted at a semantic level to make the construct clear).

Personally, I find ','.join(blahblah) quite adequate -- if I had to
use double rather than single quotes, I would indeed see an epsilon's
worth of "loss" in visual terms.


Alex

Alex Martelli

unread,
Mar 7, 2001, 4:54:15 AM3/7/01
to
"Greg Ewing" <gr...@cosc.canterbury.ac.nz> wrote in message
news:3AA58BD0...@cosc.canterbury.ac.nz...

> Alex Martelli wrote:
> >
> > No! string_join (in stringobject.c) currently just _checks_
> > PyString_Check on the items -- if any item fails that, it
> > delegates to PyUnicode_Join (if PyUnicode_Check OK's that).
>
> And that's somehow not a typeswitch? If it's a regular
> string do this... if it's a Unicode string do that...
> smells like a typeswitch to me...

It's (needlessly) coded as a typeswitch in the Python 2
sources for string_join, yes. The correct coding to
reflect the design would be to use the existing standard
interface to ask each item to _behave like_ a string,
rather than resorting to the "IS of identity" -- Korzibski's
intimations against it are perfectly valid in the context
of polymorphic programming, no less than in epistemology;
in fact, just about any test for 'IS object X of exact type
Y' you can find in the Python sources, unless they are
shortcut-like 'accelerators' for a special case _before_
the more-general request 'please o mr X try to behave like
an Y, are you able to?', can be seen as implementation
defects, in my personal opinion.

But we're arguing about the DESIGN, not the _current
implementation_ thereof, with its limitations and bugs.


> You seemed to be arguing that dispatching on the joiner
> somehow resulted in an efficiency gain by going straight
> to the right code for the kind of strings being joined,
> and I was pointing out that that's not the case. But
> maybe I misunderstood what you were saying.

The joiner-dispatch DESIGN *affords* efficiency gains;
the implementation, at one stage, may not take advantage
of the enabling-effects of a good design, but that's no
reason to make the design worse, contorting it to refect
the current limitations of an implementation!


> > You gain a clean approach, which the implementation could
> > (and should) exploit to access the items in the sequence
> > through the _appropriate_ standard interface
>
> It's only clean according to one measure of cleanness.
> It could be considered cleaner to treat all the arguments
> uniformly, and access them *all* through a standard
> interface.

And *WHAT* 'standard interface' would apply on the joiner
object, pray? The only response I see that makes sense is
"a joiner interface" -- something that the joiner object
exposes, which has a method to be called to do the join.
Which, surprise surprise, is EXACTLY what we have now --
the method in question being called 'join' (why not?!).

Note that pairwise-joining of items is NOT sufficient,
because of efficiency considerations -- O(N) versus
O(N squared). (In other terms: general joining of a
sequence may be _functionally_ constructed by iterating
a join-two-items primitive, BUT that is unacceptable as
it leads to O(N*N) performance).


> > There are NO technical costs associated with these
> > advantages.
>
> I disagree. I've mentioned one already -- it bloats the
> string object, and makes the Python core larger and
> less modular.

The string object and the string module are both in
the Python core, so moving functionality between them
can in no way be considered 'bloating'. Somebody
who's _subsetting_ the Python core is (by definition)
operating outside of Python's problem-space, and
his or her problems are not technical Python problems.


> > Only technical advantages and costs
> > can be fairly put on the balance
>
> I disagree with that, too. I think it's quite possible
> and appropriate for a small technical advantage to be
> outweighed by a larger aesthetic one. For example, there
> are technical advantages to braces instead of indentation:
> the scanner is easier to implement, it's easier to write
> programs which generate code, and there's no chance of
> space-tab confusion. On the indentation side, there's the
> advantage that indentation and block structure always
> agree. If you're counting technical advantages, that's
> one in favour of indentation and three against. But I
> doubt Guido would switch on that basis.

'Counting' technical advantages is as idiotic as 'counting'
coins as a measure of wealth -- if I have one 1-dollar
coin, and you have three 5-cent ones, such an idiot counter
would conclude that you must be richer than me by a
three to one margin. *Obviously*, the balancing of
technical considerations must take account of their
importance and relevance; a 'count' is inappropriate.

For the brace/indentation case, I would count only the
space/tab issue as being of any substantial worth -- the
miniscule extra workload on the scanner, and the need
for the output-stage of source-generators to keep track
of nesting (advisable on other grounds anyway) being
absolutely-unessential trifles. As the space/tab issue
can easily be ameliorated via tabnanny & friends, I judge
the blocking==indenting advantage strongly dominant (and
I'm happy Guido's technical evaluation is the same:-).


> > Note that I've seen NO arguments AT ALL for having
> > .join be a method on SEQUENCE object ... despite this
> > being often mentioned on an irrational-purely-aesthetical
> > basis.
>
> I don't think the basis is irrational at all. It
> seems to me that there are two quite distinct possible
> reasons for deciding to make something a method of a
> particular object.
>
> One is to get polymorphism on that object. The other

So far, so good.

> is because the object makes sense as the direct object
> (in the English grammar sense) of the operation, so
> that you can naturally read x.verb(y) as "verb x
> with y" or "verb x using y".

And here, we disagree VERY deeply. Natural language is
NO sensible basis on which to approach software design!
Please re-read Wittgenstein's works (the Philosophical
Investigations will suffice) for many deep, convincing
arguments on the issue -- W's youthful hopes to clean up
natural language of 'inappropriate superstructure' and
make it a usably solid basis for anything rigorous (as
vigorously, even brilliantly, pursued in the Tractatus)
being inevitably dashed by the deep nature of language.

Yeah, yeah, I know -- the world is full of assassinated
trees, tragically chomped into pulp for the purpose of
making paper on which such absurdities as basing software
design on natural-language foibles are _advised_. But
then, in the literature for any subject you can find many
widespread examples of both obvious and subtle absurdities.

When you do O-O design in the context of a language that
does NOT force you to express any function as a method
of something, x.verb(y) MEANS that object x has some say
(which it may of course choose to delegate) on how verb
is implemented, while object y does not necessarily have
any such implementation-freedom aspect regarding verb.
(This assumes a single-dispatch setting -- multimethods,
such as Dylan's, may change the picture drastically).

If the language forces you to express everything as a
method, then the implications are correspondingly weaker --
but, still there to some extent, since you MIGHT have
chosen to introduce a third-party object to act (to all
intent and purposes) as a 'collection of functions', to
be able to write functions.verb(x,y) and avoiding the
(supposedly undesired) dissimetry between x and y's roles.


> When these two considerations pull in the same
> direction, all is well. And with most of the string
> methods they do, but in the case of join, they don't.
> There are good reasons for not making it a method of
> the sequence, but when it is made a method of the
> joiner, the resulting expression sounds backwards[1].

Suppose I'm building a line of a CSV file, a popular
textual format where fields are separated (aka joined)
with commas -- the acronym stands for 'comma-separated
values'. So, what I want to do is
'comma-separate these values'
and, since 'separate' equates to join, this equates to:
'comma-join these values'
so, I code:
comma.join(these_values)
*WHAT'S BACKWARDS ABOUT IT*?! (Please note that the
CSV acronym IS an English one -- maybe _your_ English
native-speaker preference would have been for 'VSWC',
'Values Separated With Commas', but English native
speakers from _North_ of the Equator coined this term,
so, maybe it's a Coriolis-effect issue...?-).


> So we are faced with two alternatives, neither
> of which are entirely good. In such cases, my
> preference is not to choose either alternative --
> i.e. make join a function, not a method.

A definite technical loss on the altar of endlessly
debatable aesthetic grounds? ***Include me out***!


Alex

Alex Martelli

unread,
Mar 7, 2001, 5:11:17 AM3/7/01
to
"Carel Fellinger" <cfel...@iae.nl> wrote in message
news:983u1l$6mk$1...@animus.fel.iae.nl...
[snip]

> >>> class MixedSplitter:
> ... def __init__(self, splitter1, splitter2):
> ... self.splitter1, self.splitter2 = splitter1, splitter2
> ... def split(self, sequence):
> ... s = self.splitter1(sequence)
> ... return s[:-1] + self.splitter(s[-1])

self.splitter will give an AttributeError here (you mean .splitter2).
But you won't get here unless self.splitter1 is callable, and who
ever said it was? Guess you mean self.splitter1.split(sequence) on
the first line, and similarly self.splitter2.split on the second.

With these changes, you get no errors any more out of your code:

> >>> ms = MixedSplitter(', ', ' and ')
> >>> ms.split('1, 2, 3 and 4')
> some nasty errormessage snipped

but neither do you get what you want, because a.split(b) works
irregularly...:

-- if a is a re object, or if it's module-object os.path,
then string b is split using splitter-object a
-- if a is a string object (including a Unicode string),
then string a is split using splitter-object b (which
must also be a string)

I.e., the semantics are backwards in the two cases, alas.


> But the real evil is that no code out there will allow us to easily
> use the polimorphic nature of this splitter.

Actually, code written to split by a regular-expression object
(which it takes as an argument and only uses for splitting)
will work fine, polymorphically, with your MixedSplitter (when
the latter is amended to call the split methods of its splitter
attribute objects!-) -- as long as MixedSplitter is correctly
primed with two splitter objects, and string objects are not
splitter-objects in Python's architecture; they have a .split
method, but it doesn't work at all like those of regular expression
objects and the os.path module object do -- it's backwards.


> The moral being that we shouldn't argue about the uglines joiner.join
> but of the lack of a tru polymorphic splitter.split!

It's no doubt too late to remedy the discrepancy between
the semantics of a.split(b) depending on a's type (string
versus re) and the resulting irregularity (which we no
doubt will have to live with anyway) is unpleasant, to say
the least.


Alex

Rainer Deyke

unread,
Mar 7, 2001, 1:11:24 PM3/7/01
to
"Alex Martelli" <ale...@yahoo.com> wrote in message
news:9850g...@news1.newsguy.com...

> in fact, just about any test for 'IS object X of exact type
> Y' you can find in the Python sources, unless they are
> shortcut-like 'accelerators' for a special case _before_
> the more-general request 'please o mr X try to behave like
> an Y, are you able to?', can be seen as implementation
> defects, in my personal opinion.

I'm curious: how do you feel about the automagic conversions of functions
(and only true function, not function-like objects) into unbound methods,
and from unbound methods into bound methods? I'm thinking that the former
could be eliminated entirely, and the latter replaced by a __bind__ magic
method that allows the mechanism to apply to function-like objects.


--
Rainer Deyke (ro...@rainerdeyke.com)
Shareware computer games - http://rainerdeyke.com
"In ihren Reihen zu stehen heisst unter Feinden zu kaempfen" - Abigor


D-Man

unread,
Mar 7, 2001, 1:41:36 PM3/7/01
to pytho...@python.org
On Sat, Mar 03, 2001 at 09:29:55PM +0100, Alex Martelli wrote:
| "Russell E. Owen" <ow...@astrono.junkwashington.emu> wrote in message
| news:97p7iq$kk2$1...@nntp6.u.washington.edu...
| [snip]
| > However, I do agree that join is not intuitive. I believe the problem
| > (at least for the way I look at it) is that join should be a list
| > method, not a string method. I.e.:
| >
| > joined_string = ['a', 'b'].join(', ')
| >
| > makes a lot of sense to me. The current join string method does not.

This was my opinion as well.

|
| This seems to be a widespread opinion, and I've already tried
| to explain why my take on it differs, but that was a few months
| ago, and apparently the current crop of discussants hasn't read
| those discussions, so, let's give it one more spin.
|
| Python does not have multi-methods: it's a single-dispatch

Where can I learn about multi-methods and their
usefulness/applicability?

|
[snip]
|
| So, since we want general polymorphism on the joiner
| object, but are quite content with polymorphism through
| the standard sequence interface on the sequence object,
| it is _just right_ that .join be a method on the joiner
| object (e.g., a string) and that it take the sequence of
| string to be joined as its argument.

Ok, so instead of calling "join" a "string method" how about using the
following Java-Python hybrid snippet to describe it :

interface Joiner :
abstract Object join( Sequence s )

class String implements Joiner :
String join( Sequence s ) :
"""
oh, cool. I can mix and match the signatures sensibly without
casting ;-)
"""
...


This does make sense to me. It looks logical and reasonable. You
have convinced me Alex. Your English (and writing) classes have paid
off ;-). You must have been a writer before computers took over ;-).

-D


PS. BTW I haven't finished reading this thread yet

Steve Holden

unread,
Mar 7, 2001, 2:24:38 PM3/7/01
to
"Rainer Deyke" <ro...@rainerdeyke.com> wrote in message
news:gRup6.364652$ge4.12...@news2.rdc2.tx.home.com...

> "Alex Martelli" <ale...@yahoo.com> wrote in message
> news:9850g...@news1.newsguy.com...
> > in fact, just about any test for 'IS object X of exact type
> > Y' you can find in the Python sources, unless they are
> > shortcut-like 'accelerators' for a special case _before_
> > the more-general request 'please o mr X try to behave like
> > an Y, are you able to?', can be seen as implementation
> > defects, in my personal opinion.
>
> I'm curious: how do you feel about the automagic conversions of functions
> (and only true function, not function-like objects) into unbound methods,
> and from unbound methods into bound methods? I'm thinking that the former
> could be eliminated entirely, and the latter replaced by a __bind__ magic
> method that allows the mechanism to apply to function-like objects.
>
>
Surely no type conversion is involved: the interpreter just converts

instance.method(*args)

into

class.method(instance, *args)

regards
Steve

Mike C. Fletcher

unread,
Mar 7, 2001, 2:43:39 PM3/7/01
to pytho...@python.org
Okay, I've built a few modules now (this Python thing is fun, why didn't I
find out about it earlier ;) ), but I'm not sure I've really got the hang of
it...

http://members.home.net/mcfletch/programming/

Still haven't bought the books though. Hmm, only one I have is Win32
Programming. Was disappointing that it dealt mostly with Python, I was
hoping more for a tome containing distilled knowledge of Win32 arcana.

Enjoy yourself,
Mike


-----Original Message-----
From: Alex Martelli [mailto:ale...@yahoo.com]
Sent: Wednesday, March 07, 2001 4:01 AM
To: pytho...@python.org
Subject: Re: I come to praise .join, not to bury it...

"Mike C. Fletcher" <mcfl...@home.com> wrote in message
news:mailman.983928669...@python.org...

...


> I'll have to give that Python thing a try. Can you recommend any good
books
> for someone who's been stuck in a backwater language for the last 6 years?

My favourite books for Python beginners are:

...


D-Man

unread,
Mar 7, 2001, 3:31:42 PM3/7/01
to pytho...@python.org
On Tue, Mar 06, 2001 at 09:46:53AM -0500, Mike C. Fletcher wrote:
| Here's a professional aesthetic's take:
|
| mystring.join( )
|
| This is a perfectly normal and good-looking construct. It seems pythonic
| and beautiful, object orientation is part of Python, and this works nicely.
|
| "'".join( )
| ";".join( )
| ".".join( )
| "!".join( )
| ",".join( )
|
| All look like executable line noise. That is, the literal string's syntax
| makes the use of dotted attributes on such a string look jarring and
| off-putting. You almost expect some weird function to jump out of this
| syntax. It looks very Ruby/Perl-esque.
|

Even with my newfound understanding, provided by the Martellibot, I
agree with this. Calling a method on an object is fine. Calling it
on a literal looks weird. Take for example something like this

three = 1.__add__( 2 )

;-)


Anyways, after seeing part of the discussion here I tried a string
method on a string literal in Java and it worked as well.

I still sort of disagree with string methods like 'replace'. After
all, it doesn't really replace anything. It creates a new object with
the proper differences. Perhaps if 'replace!' were also added to
it might be clearer.

-D


D-Man

unread,
Mar 7, 2001, 3:33:30 PM3/7/01
to pytho...@python.org
On Sat, Mar 03, 2001 at 03:19:05PM -0500, Steve Holden wrote:
| "chris" <chri...@btinternet.com> wrote in message
| news:tN5o6.2746$eH3.14913@NewsReader...
| > > at latest since the 19th century; in America, it appears this is
| normally
| > > introduced in the 6th or 7th grades (ages 11-12, for those of you in
| > > inferior countries <wink>
| >
| > In Scotland that kind of stuff is pre-School! <wink-back>
| >
| > Chris
|
| Ha! As an Englishman married to a Scot I'm not going to let you get away
| with that one: this is classic Scottish braggadocio [I expect Italian
| education form tne martellibot about that]. Brass neck, as we simple
| Yorkshire folk would term it.
|

What about one who is both English and Scots, yet never set foot on
that island ;-)?

-D


Steve Williams

unread,
Mar 7, 2001, 5:08:12 PM3/7/01
to
D-Man wrote:

> On Tue, Mar 06, 2001 at 09:46:53AM -0500, Mike C. Fletcher wrote:
>

> [snip]

> Even with my newfound understanding, provided by the Martellibot, I
> agree with this. Calling a method on an object is fine. Calling it
> on a literal looks weird. Take for example something like this
>
> three = 1.__add__( 2 )
>
> ;-)
>

> Continuing on into the darkness:

ten = +.join(1,2,3,4)

and

sixfactorial = *.join(range(1,7))

Since + and * are not quoted, it's clear that 'join' is an 'arithmetic
join'--polymorphism, doncha know.

And howsabout

RatherLargeNumber == **.join(xrange(100))

The mind boggles.

Grant Edwards

unread,
Mar 7, 2001, 5:19:25 PM3/7/01
to
In article <mailman.983997159...@python.org>, D-Man wrote:

>Even with my newfound understanding, provided by the Martellibot, I
>agree with this. Calling a method on an object is fine. Calling it
>on a literal looks weird.

What makes you think a "literal" is not an object?

> Take for example something like this
>
>three = 1.__add__( 2 )

Looks just fine to a ex-Smalltalker: everything is an object.

--
Grant Edwards grante Yow! These PRESERVES
at should be FORCE-FED to
visi.com PENTAGON OFFICIALS!!

D-Man

unread,
Mar 7, 2001, 5:46:46 PM3/7/01
to pytho...@python.org
On Wed, Mar 07, 2001 at 10:19:25PM +0000, Grant Edwards wrote:
| In article <mailman.983997159...@python.org>, D-Man wrote:
|
| >Even with my newfound understanding, provided by the Martellibot, I
| >agree with this. Calling a method on an object is fine. Calling it
| >on a literal looks weird.
|
| What makes you think a "literal" is not an object?

Literals are special syntax for creating objects. So they are
objects, they just look different. I guess a better way of expressing
it is "Calling a method on a named object is fine." except it doesn't
cover objects returned by a ctor that aren't named yet.

(just for an example)
>>> from UserString import UserString
>>> UserString( "." ).join( ['a' , 'b' , 'c' ] )

-D


Paul Jackson

unread,
Mar 7, 2001, 6:09:05 PM3/7/01
to
On Tue, Mar 06, 2001 at 09:46:53AM -0500, Mike C. Fletcher wrote:
| Here's a professional aesthetic's take:
|
| mystring.join( )
|
| This is a perfectly normal and good-looking construct. It seems pythonic
| and beautiful, object orientation is part of Python, and this works nicely.
|
| "'".join( )
| ";".join( )
| ".".join( )
| "!".join( )
| ",".join( )
|
| All look like executable line noise. That is, the literal string's syntax
| makes the use of dotted attributes on such a string look jarring and
| off-putting.


Hmmmm ... the following looks nicer to the part of my
brain that agreed with the above sighting of noise:

str(",").join(x)

as in:

>>> x=['a', 'b', 'c']
>>> str(",").join(x)
'a,b,c'

But my hunch is that the above will quickly look like a silly
example of excess elaboration to a frequent reader of Python code.

Time to get used to simply:

",".join(x)

--
I won't rest till it's the best ...
Manager, Linux System Software
Paul Jackson <p...@sgi.com> 1.650.933.1373

William Park

unread,
Mar 7, 2001, 6:28:59 PM3/7/01
to pytho...@python.org
On Wed, Mar 07, 2001 at 11:09:05PM +0000, Paul Jackson wrote:
> Time to get used to simply:
>
> ",".join(x)

The best way to remember the syntax is
Using ',', join the following ['...', '...', ...].

---William Park, Open Geometry Consulting, Linux/Python, 8 CPUs.

Delaney, Timothy

unread,
Mar 7, 2001, 6:33:46 PM3/7/01
to pytho...@python.org
> comma.join()
> period.join()
> bang.join()
> etc.

What's a period? I would look at this as

comma.join()
fullstop.join()

That's one of the problems - even in English, we sometimes have completely
different words for the same symbols, let alone spelling. I mean, *why*
would you drop all the 'u's?

Tim Delaney
Avaya Australia

All recipient(s) of this email have permission to forward or reply to this
email, quoting this email in full or in part.

Steve Holden

unread,
Mar 7, 2001, 7:15:48 PM3/7/01
to
"D-Man" <dsh...@rit.edu> wrote in message
news:mailman.983997252...@python.org...

> On Sat, Mar 03, 2001 at 03:19:05PM -0500, Steve Holden wrote:
[ ... ]

>
> What about one who is both English and Scots, yet never set foot on
> that island ;-)?
>
No such animal!

regards
Steve

Terry Reedy

unread,
Mar 7, 2001, 7:19:07 PM3/7/01
to

"Steve Williams" <stevew...@wwc.com> wrote in message
news:3AA6B157...@wwc.com...

> > Continuing on into the darkness:
>
> ten = +.join(1,2,3,4)
>
> and
>
> sixfactorial = *.join(range(1,7))

We already have reduce and operator.x for these.

join:string::reduce:number -- almost

I believe that ''.join(str_list) == reduce(operator.add, str_list).

TJ Reedy

Tim Hammerquist

unread,
Mar 7, 2001, 8:21:24 PM3/7/01
to

If you refer to being "English" and "Scots" as a native only, then that may
be true.

Otherwise, you've just negated my existence!! ;)

--
-Tim Hammerquist <ti...@cpan.org>
American society is a sort of flat, fresh-water pond which absorbs
silently, without reaction, anything which is thrown into it.
-- Henry Brooks Adams

D-Man

unread,
Mar 7, 2001, 8:18:03 PM3/7/01
to pytho...@python.org

Oh. Am I a bot too? If so I must find a new maintainer so I can
match the intelligence of the other bots on the list.

;-)

-D


It is loading more messages.
0 new messages