By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
440,712 Members | 763 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 440,712 IT Pros & Developers. It's quick & easy.

High Order Messages in Python

P: n/a
I'm reading about "high order messages" in Ruby by Nat Pryce, and
thinking if it could be util and if so, if it could be done in Python.
Someone already tried?

References:
http://lambda-the-ultimate.org/node/view/1047
http://nat.truemesh.com/archives/000535.html
http://nat.truemesh.com/archives/000537.html

Oct 22 '05 #1
Share this Question
Share on Google+
12 Replies


P: n/a
Hum... I thnk you dont get the ideia: I'm not talking abou High Order
Functions.
What ho call "High Order Methods is some like "connecting" some
'generic' methods created to do things like this:
claimants.where.retired?.do.receive_benefit 50
The 2nd and 3rd links that in the first post is the most relevant to
undestand the concept. Read this too:
http://www.metaobject.com/papers/Hig...OPSLA_2005.pdf

Oct 22 '05 #2

P: n/a
This can be suitably applied to Python with the use of Higher Order
Functions, though. It's not quite the Ruby version because Python
allows you to use functions as first-class objects, complicating the
All-You-Can-Do-Is-Pass-A-Message philosophy. This is my 5-minute
implementation:
class HigherOrderList(list):

def do(self, func):
return HigherOrderList(each(self, func))

def where(self, pred):
return HigherOrderList(mass_test(self, pred))

def mass_test(iterable, pred):
for item in iterable:
if pred(item):
yield item

def each(iterable, method):
for item in iterable:
yield method(item)

Oct 22 '05 #3

P: n/a
"ed************@gmail.com" <ed************@gmail.com> writes:
I'm reading about "high order messages" in Ruby by Nat Pryce, and
thinking if it could be util and if so, if it could be done in Python.
Someone already tried?


Yes, I'm pretty sure it could be done in Python. All it really needs
is the ability to catch references to undefined attributes, which
Python has. You make the HOM of your collection class return an object
with a reference to self, and the __getattr__ method of that classs
then invokes getattr on each object in the referenced collection
instance for the undefined method, manipulating the result as
appropriate for that HOM, and returning a new list.

But this really isn't a very good fit for Python. This is really a
feature for more aggressively OO languages. To make the examples HOMs
described really useful, you want to add them to some base class for
collections. But that base class doesn't exist in Python - Python just
isn't that OO.

You could add various HOMs to lists, tuples, generators and iterators
- but then anyone who wanted to create a new sequence class would have
to add all of the HOMs that their clients might want to use. The
pythonic way would be to add a function that works with all the
various sequence types - which would then automatically work with any
user-defined classes that quacked like a sequence. It's not very OO -
but it is pythonic. In fact, Python already has functions that capture
the functionality of the example HOMs in the links you posted: where
and unless are handled by filter. in_order_of and in_reverse_order_of
are handled by sorted. do is is handled by map. Of course, recent
versions of python provide list comprehensions as preferable to some
of these functions.

That said, HOM's are a *very* powerful mechanism. The examples - and
my discussion of them - cover just one very broad use case. There may
be others where they are a better fit with Python. Having examples of
how to do these kinds of things around is probably worthwhile.

<mike
--
Mike Meyer <mw*@mired.org> http://www.mired.org/home/mwm/
Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
Oct 22 '05 #4

P: n/a
ed************@gmail.com wrote:
I'm reading about "high order messages" in Ruby by Nat Pryce, and
thinking if it could be util and if so, if it could be done in Python.


Nice sunday afternoon exercise. Yes, you can do this in python. This is
based on a relatively naive translation of the ruby version:

class HigherOrderMessage(object):
def __init__(self,handler):
self.handler = handler

class Do(HigherOrderMessage):
def __HOM__(self, methname, *args):
"implement ruby's method_missing idea"
try:
for e in self.handler:
meth = getattr(e, methname)
meth(*args)
except TypeError: # Handle non-iterator, could be nicer
if self.handler is not None:
meth = getattr(self.handler, methname)
meth(*args)
def __getattribute__(self, methname):
try:
return super(Do,self).__getattribute__(methname)
except AttributeError:
def myHom(*args):
return self.__HOM__(methname, *args)
return myHom

class Where(HigherOrderMessage):
def __HOM__(self, methname, *args):
"implement ruby's method_missing idea"
try:
r = List()
for e in self.handler:
meth = getattr(e, methname)
if meth(*args):
r.append(e)
return r
except TypeError:
r = List()
if self.handler is not None:
meth = getattr(self.handler, methname)
if meth(*args):
r.append(self.handler)
return r
#
def __getattribute__(self, methname):
"Probably belongs in the baseclass"
try:
return super(Where,self).__getattribute__(methname)
except AttributeError:
def myHom(*args):
return self.__HOM__(methname, *args)
return myHom

class enumerable(object):
def do(self): return Do(self)
def where(self): return Where(self)

class List(enumerable,list):
"List using enumerable as a mixin"

class Claimant(enumerable):
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
self.benefits = 0

def retired(self):
return (self.gender == "male" and self.age >= 65) or \
(self.gender == "female" and self.age >= 60)

def receive_benefit(self,amount):
self.benefits = self.benefits + amount

def __str__(self):
return "%s,%s age: %s benefits: %s" % (
self.name,
self.gender,
str(self.age),
str(self.benefits)
)

#
# Create an enumerable list capable of responding to
#

claimants = List([ # Just a list which is enumerable as well
Claimant("tom", 32, "male"),
Claimant("dick", 64, "male"),
Claimant("harry", 128, "male"),
Claimant("Ivanova", 32, "female"),
Claimant("Kochansky", 64, "female"),
Claimant("Sung", 128, "female"),
])

# First the normal python way I prefer this)
for claimant in claimants:
if claimant.retired():
claimant.receive_benefit(50)

# Display the results
for claimant in claimants: print str(claimant)
print

# The more direct translation of :
# claimants.select {|e| e.retired?}.each {|e| e.receive_benefit 50}

[ e.receive_benefit(50) for e in claimants if e.retired() ]

# Display the results
for claimant in claimants: print str(claimant)
print

# The single claimant version of the higher order message approach
# re-uses the last claimant from above. This one unconditionally
# grants benefits.
#
claimant.do().receive_benefit(50)
print claimant
print

# Iterating over a bunch of Claimants with the higher order message
# approach. This conditionally updates the claimaints

claimants.where().retired().do().receive_benefit(5 0)
# display results
for claimant in claimants: print str(claimant)

I'm not convinced I'd actually *use* this approach(*), but it does show that
you can certainly take this approach in python. It's certainly interesting
though.
(*) Largely because there's a bunch of magic happening as far as the user
(next programmer to edit the file) is concerned. After all you can't
find the definition of retried in "where" or "claimant"; you can't
find the definition of "receive_benefit" in "do", "retired", "where"
or "claimants".

I'm also pretty sure there's other things you'd want to do more than the
above generally speaking if you wanted to handle inheritance/etc nicely.
(That does make me wonder as well if you'd need to do more in ruby as
well)

However, this certainly isn't a case of "ruby can do this, and python
can't", because clearly python CAN do it :-)

Regards,
Michael

Oct 23 '05 #5

P: n/a
On a (somewhat) related note,
I've always wondered whether it is possible to emulate ruby blocks
using a python generator '+ alpha'. In my limited understanding of the
ruby block, the generator can inject values into a block, I suppose,
but what is the block itself? can it be a function? a class instance?
what would it look like? I am sure someone must have played around with
this.
any pointers?
cheers,
v.

Oct 24 '05 #6

P: n/a
http://www.artima.com/intv/closures.html
http://www.rubyist.net/~matz/slides/...005/index.html

It's a read-write closure, a co-routine, sort of a continuation (tho
Kernel.callcc is considered the real continuation mechanism).
And you can make it a Proc object (basically an unbound object you can
pass to methods) with Proc#new or lambda. HTH

vdrab wrote:
On a (somewhat) related note,
I've always wondered whether it is possible to emulate ruby blocks
using a python generator '+ alpha'. In my limited understanding of the
ruby block, the generator can inject values into a block, I suppose,
but what is the block itself? can it be a function? a class instance?
what would it look like? I am sure someone must have played around with
this.
any pointers?
cheers,
v.


Oct 24 '05 #7

P: n/a
could someone enlighten me what is the advantage of block over named
function ?

One thing that I can see a difference may be lexical scope ?

vdrab wrote:
On a (somewhat) related note,
I've always wondered whether it is possible to emulate ruby blocks
using a python generator '+ alpha'. In my limited understanding of the
ruby block, the generator can inject values into a block, I suppose,
but what is the block itself? can it be a function? a class instance?
what would it look like? I am sure someone must have played around with
this.
any pointers?
cheers,
v.


Oct 24 '05 #8

P: n/a
bo****@gmail.com <bo****@gmail.com> wrote:
could someone enlighten me what is the advantage of block over named
function ?

One thing that I can see a difference may be lexical scope ?


"Yes, but" -- according to the latest Ruby book, the "mixed lexical
scope" of blocks is a highly controversial notion in the Ruby community;
so I wouldn't necessarily count it as an _advantage_ of Ruby blocks...
Alex
Oct 24 '05 #9

P: n/a
counting that out(regardless whether it is (dis)advantage or not), what
else a block can do but not a named function ?

Alex Martelli wrote:
bo****@gmail.com <bo****@gmail.com> wrote:
could someone enlighten me what is the advantage of block over named
function ?

One thing that I can see a difference may be lexical scope ?


"Yes, but" -- according to the latest Ruby book, the "mixed lexical
scope" of blocks is a highly controversial notion in the Ruby community;
so I wouldn't necessarily count it as an _advantage_ of Ruby blocks...
Alex


Oct 24 '05 #10

P: n/a
bo****@gmail.com wrote:
counting that out(regardless whether it is (dis)advantage or not), what
else a block can do but not a named function ?
My limited understanding is that the advantage is
- simpler syntax
- high level of integration into the standard library (*many* methods that take closure arguments). Blocks are used not just for iteration but for the kinds of things shown in the examples to PEP 343 http://www.python.org/peps/pep-0343.html

For example to open a file and read from it uses two closures, one to wrap a block with the file open/close, one to iterate lines (from the pickaxe book):

File.open("testfile") do |file|
file.each_line { |line| puts line }
end

Kent

Alex Martelli wrote:
bo****@gmail.com <bo****@gmail.com> wrote:

could someone enlighten me what is the advantage of block over named
function ?

One thing that I can see a difference may be lexical scope ?


"Yes, but" -- according to the latest Ruby book, the "mixed lexical
scope" of blocks is a highly controversial notion in the Ruby community;
so I wouldn't necessarily count it as an _advantage_ of Ruby blocks...
Alex


Oct 24 '05 #11

P: n/a
thanks. Seems that my programs are very simple and don't need these
feature yet.

Kent Johnson wrote:
bo****@gmail.com wrote:
counting that out(regardless whether it is (dis)advantage or not), what
else a block can do but not a named function ?


My limited understanding is that the advantage is
- simpler syntax
- high level of integration into the standard library (*many* methods that take closure arguments). Blocks are used not just for iteration but for the kinds of things shown in the examples to PEP 343 http://www.python.org/peps/pep-0343.html

For example to open a file and read from it uses two closures, one to wrap a block with the file open/close, one to iterate lines (from the pickaxe book):

File.open("testfile") do |file|
file.each_line { |line| puts line }
end

Kent

Alex Martelli wrote:
bo****@gmail.com <bo****@gmail.com> wrote:
could someone enlighten me what is the advantage of block over named
function ?

One thing that I can see a difference may be lexical scope ?

"Yes, but" -- according to the latest Ruby book, the "mixed lexical
scope" of blocks is a highly controversial notion in the Ruby community;
so I wouldn't necessarily count it as an _advantage_ of Ruby blocks...
Alex



Oct 24 '05 #12

P: n/a
Kent Johnson <ke****@tds.net> wrote:
...
For example to open a file and read from it uses two closures, one to wrap
a block with the file open/close, one to iterate lines (from the pickaxe
book):

File.open("testfile") do |file|
file.each_line { |line| puts line }
end


Good example -- Ruby blocks are used both for iteration, and for
non-iterative wrapping of a single action with "try-finally" semantics.

Python's generators, up to 2.4, don't really support the non-iterative
part of this well, and have other limitations (they can get values "out"
with yield, but can't easily or naturally get results back "in"...). In
the forthcoming 2.5, Python generators will be enriched with enough
functionality for these purposes, and a new statement "with" to clearly
indicate the non-iterative case (while "for" indicates iteration).

So, in Python 2.5, the above snippet may become, in Python:

with opening("testfile") as my_file:
for line in my_file:
print line,

The fact that 2.5 will acquire extra functionality to "round out"
generators &c to the power of Ruby blocks may be taken as a clear
indication that, right now (Ruby 1.8.* vs Python 2.4.*), Ruby's blocks
are somewhat more powerful. As for the differences in style that will
remain when Python 2.5 is born, we'll be back to "personal taste" level
issues, it appears to me.
Alex
Oct 24 '05 #13

This discussion thread is closed

Replies have been disabled for this discussion.