473,722 Members | 2,155 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

generic functions in python

hi all, i'm relatively new to python. I find it a
pretty interesting language but also somewhat limiting
compared to lisp. I notice that the language does
provide a few lispy type nicities, but some very
important ones seem to be missing.

E.g., the multiple class inheritance is great,
but there are no generic functions (at least that
i can find). If i have classes X, Y, and Z,
and subclasses X_sub, Y_sub, and Z_sub respectively.

I'd love to write methods which speicialize on pairs
of these classes. It works in lisp as follows

(defmethod mymethod (( x X) ( y Y)) ;; # 1
...)

(defmethod mymethod (( x X_sub) ( y Y)) ;; # 2
...)

(defmethod mymethod (( z Z) ( x X)) ;; # 3
..)
Then for example if i call mymethod with
an instance of X_sub and Y_sub then # 2
gets called.

These multi-methods are extremely useful to the
lisp programmer.

How do python programmers work around this limitation?

One option would be to force all methods to have
a huge case statement inside them which tests
the class of the second argument. And everytime a new
class is added, all the case statements have to be
revisited and updated accordingly?

Is there a better way? perhaps there is a standard
mult-method-dispatch package available for use?

-jim

Jul 18 '05 #1
3 2894
Funny you should mention this today -- I was just sitting down to
implement generic functions myself. It tends to be the first thing I do
when learning a new language, and I'm brand new to Python.

My needs are limited, so I'm not thinking past the first pass, in which
there will be no provision for subclassing your own kinds of
Generic_Functio n and no syntactic sugar (e.g, no defmethod, just hand
intialization at load time of new methods, and hand coordination between
the function object and the Generic_Functio n object, and no
Funcallable_Ins tance class). Just basic multimethod dispatch with a simple
cache. As much as I believe Dylan's class precedence linearization is "The
Right Thing(tm)", I'll just do whatever's easiest for ordering the
classes. Anyway, I'll know more when I get into it.

When I finish (who knows when?), I'll try to remember to post here and cc
you, Jim. Please do the same with me if you come up with anything, and
please ping me after a bit if I forget.

Jim Newton wrote:
hi all, i'm relatively new to python. I find it a
pretty interesting language but also somewhat limiting
compared to lisp. I notice that the language does
provide a few lispy type nicities, but some very
important ones seem to be missing.

E.g., the multiple class inheritance is great,
but there are no generic functions (at least that
i can find). If i have classes X, Y, and Z,
and subclasses X_sub, Y_sub, and Z_sub respectively.

I'd love to write methods which speicialize on pairs
of these classes. It works in lisp as follows

(defmethod mymethod (( x X) ( y Y)) ;; # 1
...)

(defmethod mymethod (( x X_sub) ( y Y)) ;; # 2
...)

(defmethod mymethod (( z Z) ( x X)) ;; # 3
..)
Then for example if i call mymethod with
an instance of X_sub and Y_sub then # 2
gets called.

These multi-methods are extremely useful to the
lisp programmer.

How do python programmers work around this limitation?

One option would be to force all methods to have
a huge case statement inside them which tests
the class of the second argument. And everytime a new
class is added, all the case statements have to be
revisited and updated accordingly?

Is there a better way? perhaps there is a standard
mult-method-dispatch package available for use?

-jim


Jul 18 '05 #2
Hello Jim,
E.g., the multiple class inheritance is great,
but there are no generic functions (at least that
i can find). If i have classes X, Y, and Z,
and subclasses X_sub, Y_sub, and Z_sub respectively.

I'd love to write methods which speicialize on pairs
of these classes. It works in lisp as follows

(defmethod mymethod (( x X) ( y Y)) ;; # 1
...)

(defmethod mymethod (( x X_sub) ( y Y)) ;; # 2
...)

(defmethod mymethod (( z Z) ( x X)) ;; # 3
..)
Then for example if i call mymethod with
an instance of X_sub and Y_sub then # 2
gets called.


http://www-106.ibm.com/developerwork.../l-pydisp.html

HTH.
Miki.

Jul 18 '05 #3
Howard Stearns wrote:
Funny you should mention this today -- I was just sitting down to
implement generic functions myself. ...
When I finish (who knows when?), I'll try to remember to post here and
cc you, Jim.
...
Jim Newton wrote:
...
perhaps there is a standard
mult-method-dispatch package available for use?
Try this. It's only 55 lines of code plus about that many in comments. Python's pretty cool, no?

"""
Generic Functions and Methods
foo = Generic_Functio n()
foo[object, object, object] = lambda _, x, y, z: 'default'
foo[int, int, int] = lambda call_next, x, y, z: ['all ints'] + [call_next(x, y, z)]
foo[object, object] = lambda _, x, y: 'just two'
foo(1, 2, 3) ['all ints', 'default'] foo(1, 2, 'three') 'default' foo(1, 'two') 'just two' foo('oops')

Traceback (most recent call last):
...
NoNextMethod: oops
"""
_AUTHOR=["Howard Stearns (st*****@alum.m it.edu)",]
_COPYRIGHT="""
Use this for anything you want, at your own risk.
Mistakes here are Howard's fault and no one elses.
copyright 2004
As a Python newbie, I do welcome comments on style & performance, as
well as on functionality.
"""
"""
There are several simplifications here compared with, say,
http://www.lisp.org/table/references.htm#mop
- FIXME: Currently, no support for **key args.
- No method or class metaobjects or mop.
- No support for method combination, or for before/after methods:
But there is a call-next-method mechanism, so you can assemble your own
results as you like.
- No real support for subclassing new kinds of generic functions with their
own mechanisms.
And there is one extension:
+ Instead of dispatching only on the classes of a fixed number of positional
arguments, dispatch is on both the number and type of arguments.

Class precence order is as defined by Python getmro().

David Mertz has a nice package at
http://www-106.ibm.com/developerwork.../l-pydisp.html
* This one differs in that there is only a single (powerful?) mechanism for
method combination (call-next-method) instead of a built-in list option.
* Generic_Functio n() instances here are also dict objects, and you add/replace
method by setting them using the signature as a key.
* This implementation builds a cache of effective methods instead of computing
dispatches again for each call, so this is a lot faster.
"""

from UserDict import UserDict
from inspect import getmro

class NoNextMethod(Ex ception): pass

def raise_NoNextMet hod(*args):
raise NoNextMethod, args

class Generic_Functio n(UserDict, object):
"""A function that can have different method bodies separately defined.
"""
def __init__(self):
self.data = {} # All raw methods that have been defined.
self.reset()
def reset(self):
self.cache = {} # Combined methods that have actually been called.
# Being a dict, my_func[typeA, typeB, ...] gives the method for those types.
def __setitem__(sel f, signature, method_function ):
"""Add or replace a method.

e.g., my_func[Type1, Type2, ...] = lambda call_next, arg1, arg2, ...: body
Within the body of the method, call_next is a function with the same
signature as the whole generic function. It executes the next more general
method that applies to the given arguments.
"""
self.reset() # Whenever we add a method, it invalidates the cache.
UserDict.__seti tem__(self, signature, method_function )
def __call__(self, *dispatch_args) :
actual_types = tuple(map(type, dispatch_args))
effective_metho d = self.cache.get( actual_types)
if effective_metho d == None:
effective_metho d = self.compute_ef fective_method( actual_types)
self.cache[actual_types] = effective_metho d
return effective_metho d(*dispatch_arg s)
# The next two could reasonably be changed in subclasses to provide different behavior.
def compute_effecti ve_method(self, classes):
"""Uses the applicable method function to produce a single effective method.

A method function takes a call_next argument. See __setitem___.
An effective method has the same signature as the generic function, and is
suitable as a call_next argument to a method function.
"""
applicable_meth ods = self.compute_ap plicable_method s(classes)
if applicable_meth ods == []:
return raise_NoNextMet hod
else:
return self.compute_ef fective_method_ from_list(appli cable_methods)
def compute_applica ble_methods(sel f, classes):
pairs = []
for signature, method in self.data.iteri tems():
if self.sig_applie s_p(signature, classes):
pairs.append((s ignature, method))
pairs.sort(lamb da a, b: self.cmp_sigs_r elative_to_arg_ types(a[0], b[0], classes))
methods = []
return [pair[1] for pair in pairs]
# Utilities ...
def sig_applies_p(s elf, method_sig, arg_types):
"""True if each of method_sig is subclass of each of arg_types, for all of arg_types."""
return reduce((lambda r, (a, b): r and (a!=None) and (b!=None) and issubclass(a, b)),
map(None, arg_types, method_sig),
True)
def cmp_sigs_relati ve_to_arg_types (self, sig_a, sig_b, arg_types):
"""At the first place where sig_a and sig_b differ, which comes first
in the full class precedence list of the corresponding type in arg_types."""
as, bs = list(sig_a), list(sig_b)
for arg_type in arg_types:
a = as.pop(0)
b = bs.pop(0)
if a != b:
class_precedenc e_list = list(getmro(arg _type))
return class_precedenc e_list.index(a) - class_precedenc e_list.index(b)
def compute_effecti ve_method_from_ list(self, method_function s):
"""Converts a sequence of supplied method functions to a single effective method function."""
rest = method_function s[1:]
if rest == []:
call_next = raise_NoNextMet hod
else:
more = self.compute_ef fective_method_ from_list(rest)
call_next = lambda *args: more(*args)
return lambda *args: method_function s[0](call_next, *args)

def _test():
import doctest, Generic_Functio n
return doctest.testmod (Generic_Functi on)

if __name__ == "__main__":
_test()

Jul 18 '05 #4

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

4
1977
by: Edward Diener | last post by:
Version 2.0 of the Python database API was written over 5 years ago, in 1999. While it has been used successfully by many implementations, there is no generic access into the data dictionary of relational databases except at the table column level. I am working on some Python which would hopefully give me a form of generic access to more common data dictionary functionality such as indices, constraints etc. but no such functionality...
16
9726
by: Roman Suzi | last post by:
Hi, I wonder, does Python support generic programming paradigm, and to what extent (I guess, it doesn't do it in full)? And (or) does it move in that direction? Will we ever see concept WellAlright: ... constructs in Python?
35
2335
by: Gabriel Zachmann | last post by:
Is there any generic way to use C++ libraries from within Python. I seem to recall that there are tools to generate wrappers for C-libraries semi-automatically. But those were still way too cumbersome, IMHO. What I would like to have is some module (or whatever), with which I can say "load this C++ library", and then, "create that C++ object" or "call method x of C++ object y".
49
2884
by: Steven Bethard | last post by:
I promised I'd put together a PEP for a 'generic object' data type for Python 2.5 that allows one to replace __getitem__ style access with dotted-attribute style access (without declaring another class). Any comments would be appreciated! Thanks! Steve ----------------------------------------------------------------------
0
2347
by: Carlo Milanesi | last post by:
Let's say I want to write the following function, void f(const list<int> &l, const vector<int> &v) { cout << get_second(l) << '\n'; cout << get_second(v) << '\n'; cout << get_nth(l, 2) << '\n'; cout << get_nth(v, 2) << '\n'; } that prints the second and third (counting from zero) items of given
4
4428
by: Leslaw Bieniasz | last post by:
Cracow, 20.10.2004 Hello, As far as I understand, the generic programming basically consists in using templates for achieving a static polymorphism of the various code fragments, and their reuse for various template parameters. I wonder if there exist techniques for achieving a dynamic polymorphism using the generic programming. Is this possible? If yes, can anyone show me simple examples in C++
0
1182
by: fj | last post by:
I am new in Python programming. I try to connect to Python various libraries written either in C of in Fortran. The job is not really hard but I meet a trouble when trying to build up a generic routine like in C++ or F90, i.e. a single routine name for various uses. Here is an example with a Fortran 77 library: static PyObject* mdb_get(PyObject *self, PyObject *args){ const char *cname,*cprop; int lname,lprop;
2
2294
by: Nadeem Afroz | last post by:
Hello Folks!!!! i have one interesting question over here .......... Is it possible to create a generic pointer (generic pointer to member functions) which can point to all the member functions of a class Ex : class abc() { int fun1(int a)
26
3615
by: raylopez99 | last post by:
Here is a good example that shows generic delegate types. Read this through and you'll have an excellent understanding of how to use these types. You might say that the combination of the generic delegate type expression in just the right place and a well-named method means we can almost read the code out loud and understand it without even thinking. Note that since 'boxing' and 'unboxing' is involved (I think), you don't get what you...
0
9384
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
9088
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
8052
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
6681
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
5995
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
4502
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
4762
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
3207
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
2602
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.