Python equivalent of Common Lisp Macros?

D

dpapathanasiou

I'm using the feedparser library to extract data from rss feed items.

After I wrote this function, which returns a list of item titles, I
noticed that most item attributes would be retrieved the same way,
i.e., the function would look exactly the same, except for the single
data.append line inside the for loop.

In CL, I could simply write a macro, then replace the data.append line
depending on which attribute I wanted.

Is there anything similar in Python?

Here's the function:

def item_titles (feed_url):
"""Return a list of the item titles found in this feed url"""
data = []
feed = feedparser.parse(feed_url)
if feed:
if len(feed.version) > 0:
for e in feed.entries:
data.append(e.title.encode('utf-8'))
return data
 
D

Diez B. Roggisch

dpapathanasiou said:
I'm using the feedparser library to extract data from rss feed items.

After I wrote this function, which returns a list of item titles, I
noticed that most item attributes would be retrieved the same way,
i.e., the function would look exactly the same, except for the single
data.append line inside the for loop.

In CL, I could simply write a macro, then replace the data.append line
depending on which attribute I wanted.

Is there anything similar in Python?

Here's the function:

def item_titles (feed_url):
"""Return a list of the item titles found in this feed url"""
data = []
feed = feedparser.parse(feed_url)
if feed:
if len(feed.version) > 0:
for e in feed.entries:
data.append(e.title.encode('utf-8'))
return data

No, there are no macros. Yet it has - amongst other options, such as
callbacks - decorators, that would allow you to write your code like this:

def items (feed_url):
feed = feedparser.parse(feed_url)
if feed:
if len(feed.version) > 0:
for e in feed.entries:
yield e


titles = []
other_things = []
for item in items(url):
titles.append(item.title.encode('utf-8'))
other_things.append(item.other_thing)

Diez
 
C

Chris Rebert

I'm using the feedparser library to extract data from rss feed items.

After I wrote this function, which returns a list of item titles, I
noticed that most item attributes would be retrieved the same way,
i.e., the function would look exactly the same, except for the single
data.append line inside the for loop.

In CL, I could simply write a macro, then replace the data.append line
depending on which attribute I wanted.

Is there anything similar in Python?

Yes, use higher-order functions. See below.
Here's the function:

def item_titles (feed_url):
Replace previous line with:
def item_titles(feed_url, attr_getter):
"""Return a list of the item titles found in this feed url"""
data = []
feed = feedparser.parse(feed_url)
if feed:
if len(feed.version) > 0:
for e in feed.entries:
data.append(e.title.encode('utf-8'))
Replace previous line with:
data.append(attr_getter(e))
return data

Example usage:

def title_getter(entry):
return entry.title.encode('utf-8')

titles = item_titles("some feed url here", title_getter)

As I'm not familiar with feedparser, you might want to move where the
..encode() takes place, but you get the idea.

Cheers,
Chris[/QUOTE]
 
A

Arnaud Delobelle

dpapathanasiou said:
I'm using the feedparser library to extract data from rss feed items.

After I wrote this function, which returns a list of item titles, I
noticed that most item attributes would be retrieved the same way,
i.e., the function would look exactly the same, except for the single
data.append line inside the for loop.

In CL, I could simply write a macro, then replace the data.append line
depending on which attribute I wanted.

Is there anything similar in Python?

Here's the function:

def item_titles (feed_url):
"""Return a list of the item titles found in this feed url"""
data = []
feed = feedparser.parse(feed_url)
if feed:
if len(feed.version) > 0:
for e in feed.entries:
data.append(e.title.encode('utf-8'))
return data

Something like this?

def item_attrs (feed_url, attr):
"""Return a list of the item titles found in this feed url"""
data = []
feed = feedparser.parse(feed_url)
if feed:
if len(feed.version) > 0:
for e in feed.entries:
data.append(getattr(e, attr).encode('utf-8'))
return data

You're not making it clear how the data.append... line changes so it's
hard to know exactly.
 
J

J Kenneth King

dpapathanasiou said:
I'm using the feedparser library to extract data from rss feed items.

After I wrote this function, which returns a list of item titles, I
noticed that most item attributes would be retrieved the same way,
i.e., the function would look exactly the same, except for the single
data.append line inside the for loop.

In CL, I could simply write a macro, then replace the data.append line
depending on which attribute I wanted.

Is there anything similar in Python?

Here's the function:

def item_titles (feed_url):
"""Return a list of the item titles found in this feed url"""
data = []
feed = feedparser.parse(feed_url)
if feed:
if len(feed.version) > 0:
for e in feed.entries:
data.append(e.title.encode('utf-8'))
return data

No macros -- need the whole "code as data" paradigm which doesn't exist
in python.

The pythonic way to create the sort of abstraction you're looking for
would be to use the *attr functions and either a map of attribute
identities or inspect the attributes from the objects.

Some UNTESTED code...

def extract_entry(e, attrs=['title', 'datetime', 'article']):
out = []
for attr in attrs:
assert hasattr(e, attr)
out.append(getattr(e, attr))
return out

Using the inspect module would give an even more generic function, but
with more complex code of course.

Then your code would look more like:

def items(feed_url):
feed = feedparser.feed(feed_url)
if feed and len(feed) > 0:
return [extract_entry(entry) for entry in feed.entries]

Of course, I'm making liberal assumptions about what you're looking for
in your ouput here... but it's just an example, not a full
solution. YMMV. Hope it helps. :)
 
D

dpapathanasiou

I'm using the feedparser library to extract data from rss feed items.
After I wrote this function, which returns a list of item titles, I
noticed that most item attributes would be retrieved the same way,
i.e., the function would look exactly the same, except for the single
data.append line inside the for loop.
In CL, I could simply write a macro, then replace the data.append line
depending on which attribute I wanted.
Is there anything similar in Python?

Yes, use higher-order functions. See below.


Here's the function:
def item_titles (feed_url):

Replace previous line with:
def item_titles(feed_url, attr_getter):> """Return a list of the item titles found in this feed url"""
data = []
feed = feedparser.parse(feed_url)
if feed:
if len(feed.version) > 0:
for e in feed.entries:
data.append(e.title.encode('utf-8'))

Replace previous line with:
data.append(attr_getter(e))
return data

Example usage:

def title_getter(entry):
return entry.title.encode('utf-8')

titles = item_titles("some feed url here", title_getter)

Thanks; this is exactly what I was looking for.
 

Ask a Question

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

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

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,051
Latest member
CarleyMcCr

Latest Threads

Top