SimplePrograms challenge

S

Steve Howell

Hi, I'm offering a challenge to extend the following
page by one good example:

http://wiki.python.org/moin/SimplePrograms

Right now the page starts off with 15 examples that
cover lots of ground in Python, but they're still
scratching the surface. (There are also two Eight
Queens implementations, but I'm looking to fill the
gap in lines-of-code, and they're a little long now.)

I'm looking for a good 16-line code example with the
following qualities:

1) It introduces some important Python concept that
the first 15 programs don't cover.

2) It's not too esoteric. Python newbies are the
audience (but you can assume they're not new to
programming in general).

3) It runs on Python 2.4.

4) It doesn't just demonstrate a concept; it solves
a problem at face value. (It can solve a whimsical
problem, like counting rabbits, but the program itself
should be "complete" and "suitably simple" for the
problem at hand.)

5) You're willing to have your code reviewed by the
masses.

6) No major departures from PEP 8.

Any takers?

-- Steve







____________________________________________________________________________________
Looking for a deal? Find great prices on flights and hotels with Yahoo! FareChase.
http://farechase.yahoo.com/
 
I

infidel

# reading CSV files, tuple-unpacking
import csv

#pacific.csv contains:
#1,CA,California
#2,AK,Alaska
#3,OR,Oregon
#4,WA,Washington
#5,HI,Hawaii

reader = csv.reader(open('pacific.csv'))
for id, abbr, name in reader:
print '%s is abbreviated: "%s"' % (name, abbr)
 
?

=?iso-8859-1?B?QW5kcuk=?=

Hi, I'm offering a challenge to extend the following
page by one good example:

http://wiki.python.org/moin/SimplePrograms

Right now the page starts off with 15 examples that
cover lots of ground in Python, but they're still
scratching the surface. (There are also two Eight
Queens implementations, but I'm looking to fill the
gap in lines-of-code, and they're a little long now.)

I'm looking for a good 16-line code example with the
following qualities:

1) It introduces some important Python concept that
the first 15 programs don't cover.

2) It's not too esoteric. Python newbies are the
audience (but you can assume they're not new to
programming in general).

3) It runs on Python 2.4.

4) It doesn't just demonstrate a concept; it solves
a problem at face value. (It can solve a whimsical
problem, like counting rabbits, but the program itself
should be "complete" and "suitably simple" for the
problem at hand.)

5) You're willing to have your code reviewed by the
masses.

6) No major departures from PEP 8.

Any takers?

Ok, doctest-based version of the Unit test example added; so much more
Pythonic ;-)

André

P.S. Congrats for starting this!
 
J

John Machin

# reading CSV files, tuple-unpacking
import csv

#pacific.csv contains:
#1,CA,California
#2,AK,Alaska
#3,OR,Oregon
#4,WA,Washington
#5,HI,Hawaii

reader = csv.reader(open('pacific.csv'))

For generality and portability, this should be:
reader = csv.reader(open('pacific.csv', 'rb'))
for id, abbr, name in reader:
print '%s is abbreviated: "%s"' % (name, abbr)

and this example doesn't demonstrate why one should use the csv module
instead of:
for line in open('pacific.csv'):
id, abbr, name = line.rstrip().split(',')
# etc
which is quite adequate for the simplistic example file.
 
J

John Machin

One more suggestion--maybe it could exercise a little
more of the CVS module, i.e. have something in the
data that would trip up the ','.split() approach?

The what approach?? Do you mean blah.split(',') ??

Perhaps like an example I posted a few days ago:

"Jack ""The Ripper"" Jones","""Eltsac Ruo"", 123 Smith St",,Paris TX
12345
(name and 3 address fields)
[for avoidance of doubt caused by line wrapping, repr(last_field) is
'Paris TX 12345', and the 2nd-last is '']
 
M

mensanator

Hi, I'm offering a challenge to extend the following
page by one good example:

http://wiki.python.org/moin/SimplePrograms

Right now the page starts off with 15 examples that
cover lots of ground in Python, but they're still
scratching the surface. (There are also two Eight
Queens implementations, but I'm looking to fill the
gap in lines-of-code, and they're a little long now.)

I'm looking for a good 16-line code example with the
following qualities:

1) It introduces some important Python concept that
the first 15 programs don't cover.

2) It's not too esoteric. Python newbies are the
audience (but you can assume they're not new to
programming in general).

3) It runs on Python 2.4.

4) It doesn't just demonstrate a concept; it solves
a problem at face value. (It can solve a whimsical
problem, like counting rabbits, but the program itself
should be "complete" and "suitably simple" for the
problem at hand.)

5) You're willing to have your code reviewed by the
masses.

6) No major departures from PEP 8.

Any takers?

-- Steve

___________________________________________________________________________ _________
Looking for a deal? Find great prices on flights and hotels with Yahoo! FareChase.http://farechase.yahoo.com/

I just posted a 30-line generator function
on your site. Should I have posted it here
first? Also, why do you count comments and
blank lines instead of lines of executable
code? Are you trying to encourage obfuscation?
 
R

Rob Wolfe

Steve said:
Hi, I'm offering a challenge to extend the following
page by one good example:

http://wiki.python.org/moin/SimplePrograms

What about simple HTML parsing? As a matter of fact this is not
language concept, but shows the power of Python standard library.
Besides, that's very popular problem among newbies. This program
for example shows all the linked URLs in the HTML document:

<code>
from HTMLParser import HTMLParser

page = '''
<html><head><title>URLs</title></head>
<body>
<ul>
<li><a href="http://domain1/page1">some page1</a></li>
<li><a href="http://domain2/page2">some page2</a></li>
</ul>
</body></html>
'''

class URLLister(HTMLParser):
def reset(self):
HTMLParser.reset(self)
self.urls = []

def handle_starttag(self, tag, attrs):
try:
# get handler for tag and call it e.g. self.start_a
getattr(self, "start_%s" % tag)(attrs)
except AttributeError:
pass

def start_a(self, attrs):
href = [v for k, v in attrs if k == "href"]
if href:
self.urls.extend(href)

parser = URLLister()
parser.feed(page)
parser.close()
for url in parser.urls: print url
</code>
 
S

Steven Bethard

Rob said:
What about simple HTML parsing? As a matter of fact this is not
language concept, but shows the power of Python standard library.
Besides, that's very popular problem among newbies. This program
for example shows all the linked URLs in the HTML document:

<code>
from HTMLParser import HTMLParser

[Sorry if this comes twice, it didn't seem to be showing up]

I'd hate to steer a potential new Python developer to a clumsier library
when Python 2.5 includes ElementTree::

import xml.etree.ElementTree as etree

page = '''
<html><head><title>URLs</title></head>
<body>
<ul>
<li><a href="http://domain1/page1">some page1</a></li>
<li><a href="http://domain2/page2">some page2</a></li>
</ul>
</body></html>
'''

tree = etree.fromstring(page)
for a_node in tree.getiterator('a'):
url = a_node.get('href')
if url is not None:
print url

I know that the wiki page is supposed to be Python 2.4 only, but I'd
rather have no example than an outdated one.

STeVe
 
R

Rob Wolfe

Steven Bethard said:
I'd hate to steer a potential new Python developer to a clumsier

"clumsier"???
Try to parse this with your program:

page2 = '''
<html><head><title>URLs</title></head>
<body>
<ul>
<li><a href="http://domain1/page1">some page1</a></li>
<li><a href="http://domain2/page2">some page2</a></li>
library when Python 2.5 includes ElementTree::

import xml.etree.ElementTree as etree

page = '''
<html><head><title>URLs</title></head>
<body>
<ul>
<li><a href="http://domain1/page1">some page1</a></li>
<li><a href="http://domain2/page2">some page2</a></li>
</ul>
</body></html>
'''

tree = etree.fromstring(page)
for a_node in tree.getiterator('a'):
url = a_node.get('href')
if url is not None:
print url

It might be even one-liner:
print "\n".join((url.get('href', '') for url in tree.findall(".//a")))

But as far as HTML (not XML) is concerned this is not very realistic solution.
I know that the wiki page is supposed to be Python 2.4 only, but I'd
rather have no example than an outdated one.

This example is by no means "outdated".
 
S

Steven Bethard

Rob said:
"clumsier"???
Try to parse this with your program:

page2 = '''
<html><head><title>URLs</title></head>
<body>
<ul>
<li><a href="http://domain1/page1">some page1</a></li>
<li><a href="http://domain2/page2">some page2</a></li>
</body></html>
'''

If you want to parse invalid HTML, I strongly encourage you to look into
BeautifulSoup. Here's the updated code:

import ElementSoup # http://effbot.org/zone/element-soup.htm
import cStringIO

tree = ElementSoup.parse(cStringIO.StringIO(page2))
for a_node in tree.getiterator('a'):
url = a_node.get('href')
if url is not None:
print url
This example is by no means "outdated".

Given the simplicity of the ElementSoup code above, I'd still contend
that using HTMLParser here shows too complex an answer to too simple a
problem.

STeVe
 
S

Steven Bethard

Steven said:
If you want to parse invalid HTML, I strongly encourage you to look into
BeautifulSoup. Here's the updated code:

import ElementSoup # http://effbot.org/zone/element-soup.htm
import cStringIO

tree = ElementSoup.parse(cStringIO.StringIO(page2))
for a_node in tree.getiterator('a'):
url = a_node.get('href')
if url is not None:
print url

I should also have pointed out that using the above ElementSoup code can
parse the following text::

<html><head><title>URLs</title></head>
<body>
<ul>
<li<a href="http://domain1/page1">some page1</a></li>
<li><a href="http://domain2/page2">some page2</a></li>
</body></html>

where the HTMLParser code raises an HTMLParseError.

STeVe
 
G

George Sakkis

Hi, I'm offering a challenge to extend the following
page by one good example:

http://wiki.python.org/moin/SimplePrograms

Right now the page starts off with 15 examples that
cover lots of ground in Python, but they're still
scratching the surface. (There are also two Eight
Queens implementations, but I'm looking to fill the
gap in lines-of-code, and they're a little long now.)

I'm looking for a good 16-line code example with the
following qualities:

1) It introduces some important Python concept that
the first 15 programs don't cover.

2) It's not too esoteric. Python newbies are the
audience (but you can assume they're not new to
programming in general).

3) It runs on Python 2.4.

4) It doesn't just demonstrate a concept; it solves
a problem at face value. (It can solve a whimsical
problem, like counting rabbits, but the program itself
should be "complete" and "suitably simple" for the
problem at hand.)

5) You're willing to have your code reviewed by the
masses.

6) No major departures from PEP 8.

Any takers?

-- Steve

I love the 7-line version of the prime number generator by Tim
Hochberg at the last comment of http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/117119:

from itertools import count, ifilter
def sieve():
seq = count(2)
while True:
p = seq.next()
seq = ifilter(p.__rmod__, seq)
yield p


I suspect that it violates your second rule though :)

George
 
S

Stefan Behnel

Steven said:
If you want to parse invalid HTML, I strongly encourage you to look into
BeautifulSoup. Here's the updated code:

import ElementSoup # http://effbot.org/zone/element-soup.htm
import cStringIO

tree = ElementSoup.parse(cStringIO.StringIO(page2))
for a_node in tree.getiterator('a'):
url = a_node.get('href')
if url is not None:
print url


Given the simplicity of the ElementSoup code above, I'd still contend
that using HTMLParser here shows too complex an answer to too simple a
problem.

Here's an lxml version:

from lxml import etree as et # http://codespeak.net/lxml
html = et.HTML(page2)
for href in html.xpath("//a/@href[string()]"):
print href

Doesn't count as a 15-liner, though, even if you add the above HTML code to it.

Stefan
 
S

Steven Bethard

Stefan said:
Steven said:
If you want to parse invalid HTML, I strongly encourage you to look into
BeautifulSoup. Here's the updated code:

import ElementSoup # http://effbot.org/zone/element-soup.htm
import cStringIO

tree = ElementSoup.parse(cStringIO.StringIO(page2))
for a_node in tree.getiterator('a'):
url = a_node.get('href')
if url is not None:
print url
[snip]

Here's an lxml version:

from lxml import etree as et # http://codespeak.net/lxml
html = et.HTML(page2)
for href in html.xpath("//a/@href[string()]"):
print href

Doesn't count as a 15-liner, though, even if you add the above HTML code to it.

Definitely better than the HTMLParser code. =) Personally, I still
prefer the xpath-less version, but that's only because I can never
remember what all the line noise characters in xpath mean. ;-)

STeVe
 
R

Rob Wolfe

Steve said:
I suggested earlier that maybe we post multiple
solutions. That makes me a little nervous, to the
extent that it shows that the Python community has a
hard time coming to consensus on tools sometimes.

We agree that BeautifulSoup is the best for parsing HTML. :)
This is not a completely unfair knock on Python,
although I think the reason multiple solutions tend to
emerge for this type of thing is precisely due to the
simplicity and power of the language itself.

So I don't know. What about trying to agree on an XML
parsing example instead?

Thoughts?

I vote for example with ElementTree (without xpath)
with a mention of using ElementSoup for invalid HTML.
 
S

Steven Bethard

Rob said:
We agree that BeautifulSoup is the best for parsing HTML. :)


I vote for example with ElementTree (without xpath)
with a mention of using ElementSoup for invalid HTML.

Sounds good to me. Maybe something like::

import xml.etree.ElementTree as etree
dinner_recipe = '''
<ingredients>
<ing><amt><qty>24</qty><unit>slices</unit></amt><item>baguette</item></ing>
<ing><amt><qty>2+</qty><unit>tbsp</unit></amt><item>olive_oil</item></ing>
<ing><amt><qty>1</qty><unit>cup</unit></amt><item>tomatoes</item></ing>
<ing><amt><qty>1-2</qty><unit>tbsp</unit></amt><item>garlic</item></ing>
<ing><amt><qty>1/2</qty><unit>cup</unit></amt><item>Parmesan</item></ing>
<ing><amt><qty>1</qty><unit>jar</unit></amt><item>pesto</item></ing>
</ingredients>'''
pantry = set(['olive oil', 'pesto'])
tree = etree.fromstring(dinner_recipe)
for item_elem in tree.getiterator('item'):
if item_elem.text not in pantry:
print item_elem.text

Though I wouldn't know where to put the ElementSoup link in this one...

STeVe
 
R

Rob Wolfe

Steven Bethard said:
Sounds good to me. Maybe something like::

import xml.etree.ElementTree as etree
dinner_recipe = '''
<ingredients>
<ing><amt><qty>24</qty><unit>slices</unit></amt><item>baguette</item></ing>
<ing><amt><qty>2+</qty><unit>tbsp</unit></amt><item>olive_oil</item></ing>
^^^^^^^^^

Is that a typo here?
<ing><amt><qty>1</qty><unit>cup</unit></amt><item>tomatoes</item></ing>
<ing><amt><qty>1-2</qty><unit>tbsp</unit></amt><item>garlic</item></ing>
<ing><amt><qty>1/2</qty><unit>cup</unit></amt><item>Parmesan</item></ing>
<ing><amt><qty>1</qty><unit>jar</unit></amt><item>pesto</item></ing>
</ingredients>'''
pantry = set(['olive oil', 'pesto'])
tree = etree.fromstring(dinner_recipe)
for item_elem in tree.getiterator('item'):
if item_elem.text not in pantry:
print item_elem.text

That's nice example. :)
Though I wouldn't know where to put the ElementSoup link in this one...

I had a regular HTML in mind, something like:

<code>
# HTML page
dinner_recipe = '''
<html><head><title>Recipe</title></head><body>
<table>
<tr><th>amt</th><th>unit</th><th>item</th></tr>
<tr><td>24</td><td>slices</td><td>baguette</td></tr>
<tr><td>2+</td><td>tbsp</td><td>olive_oil</td></tr>
<tr><td>1</td><td>cup</td><td>tomatoes</td></tr>
<tr><td>1-2</td><td>tbsp</td><td>garlic</td></tr>
<tr><td>1/2</td><td>cup</td><td>Parmesan</td></tr>
<tr><td>1</td><td>jar</td><td>pesto</td></tr>
</table>
</body></html>'''

# program
import xml.etree.ElementTree as etree
tree = etree.fromstring(dinner_recipe)

#import ElementSoup as etree # for invalid HTML
#from cStringIO import StringIO # use this
#tree = etree.parse(StringIO(dinner_recipe)) # wrapper for BeautifulSoup

pantry = set(['olive oil', 'pesto'])

for ingredient in tree.getiterator('tr'):
amt, unit, item = ingredient.getchildren()
if item.tag == "td" and item.text not in pantry:
print "%s: %s %s" % (item.text, amt.text, unit.text)
</code>

But if that's too complicated I will not insist on this. :)
Your example is good enough.
 
S

Steven Bethard

Rob said:
^^^^^^^^^
Is that a typo here?

Just trying to make Thunderbird line-wrap correctly. ;-) It's better
with a space instead of an underscore.
<ing><amt><qty>1</qty><unit>cup</unit></amt><item>tomatoes</item></ing>
<ing><amt><qty>1-2</qty><unit>tbsp</unit></amt><item>garlic</item></ing>
<ing><amt><qty>1/2</qty><unit>cup</unit></amt><item>Parmesan</item></ing>
<ing><amt><qty>1</qty><unit>jar</unit></amt><item>pesto</item></ing>
</ingredients>'''
pantry = set(['olive oil', 'pesto'])
tree = etree.fromstring(dinner_recipe)
for item_elem in tree.getiterator('item'):
if item_elem.text not in pantry:
print item_elem.text

That's nice example. :)
Though I wouldn't know where to put the ElementSoup link in this one...

I had a regular HTML in mind, something like:

<code>
# HTML page
dinner_recipe = '''
<html><head><title>Recipe</title></head><body>
<table>
<tr><th>amt</th><th>unit</th><th>item</th></tr>
<tr><td>24</td><td>slices</td><td>baguette</td></tr>
<tr><td>2+</td><td>tbsp</td><td>olive_oil</td></tr>
<tr><td>1</td><td>cup</td><td>tomatoes</td></tr>
<tr><td>1-2</td><td>tbsp</td><td>garlic</td></tr>
<tr><td>1/2</td><td>cup</td><td>Parmesan</td></tr>
<tr><td>1</td><td>jar</td><td>pesto</td></tr>
</table>
</body></html>'''

# program
import xml.etree.ElementTree as etree
tree = etree.fromstring(dinner_recipe)

#import ElementSoup as etree # for invalid HTML
#from cStringIO import StringIO # use this
#tree = etree.parse(StringIO(dinner_recipe)) # wrapper for BeautifulSoup

pantry = set(['olive oil', 'pesto'])

for ingredient in tree.getiterator('tr'):
amt, unit, item = ingredient.getchildren()
if item.tag == "td" and item.text not in pantry:
print "%s: %s %s" % (item.text, amt.text, unit.text)
</code>

But if that's too complicated I will not insist on this. :)
Your example is good enough.

Sure, that looks fine to me. =)

Steve
 
I

infidel

# writing/reading CSV files, tuple-unpacking, cmp() built-in
import csv

writer = csv.writer(open('stocks.csv', 'wb'))
writer.writerows([
('GOOG', 'Google, Inc.', 505.24, 0.47, 0.09),
('YHOO', 'Yahoo! Inc.', 27.38, 0.33, 1.22),
('CNET', 'CNET Networks, Inc.', 8.62, -0.13, -1.49)
])

stocks = csv.reader(open('stocks.csv', 'rb'))
for ticker, name, price, change, pct in stocks:
print '%s is %s (%s%%)' % (
name,
{-1: 'down', 0: 'unchanged', 1: 'up'}[cmp(float(change),
0.0)],
pct
)
 
S

Steven Bethard

Rob said:
# HTML page
dinner_recipe = '''
<html><head><title>Recipe</title></head><body>
<table>
<tr><th>amt</th><th>unit</th><th>item</th></tr>
<tr><td>24</td><td>slices</td><td>baguette</td></tr>
<tr><td>2+</td><td>tbsp</td><td>olive_oil</td></tr>
<tr><td>1</td><td>cup</td><td>tomatoes</td></tr>
<tr><td>1-2</td><td>tbsp</td><td>garlic</td></tr>
<tr><td>1/2</td><td>cup</td><td>Parmesan</td></tr>
<tr><td>1</td><td>jar</td><td>pesto</td></tr>
</table>
</body></html>'''

# program
import xml.etree.ElementTree as etree
tree = etree.fromstring(dinner_recipe)

#import ElementSoup as etree # for invalid HTML
#from cStringIO import StringIO # use this
#tree = etree.parse(StringIO(dinner_recipe)) # wrapper for BeautifulSoup

pantry = set(['olive oil', 'pesto'])

for ingredient in tree.getiterator('tr'):
amt, unit, item = ingredient.getchildren()
if item.tag == "td" and item.text not in pantry:
print "%s: %s %s" % (item.text, amt.text, unit.text)

I posted a slight variant of this, trimmed down a bit to 21 lines.

STeVe
 

Ask a Question

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

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

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,011
Latest member
AjaUqq1950

Latest Threads

Top