I also thought it would be nifty if Python had them so I got the source
from the CVS respository and started hacking the grammar and realized I
had no idea what I was doing :-).
Before getting in any deeper in something I only vaguely understand I
thought I would ask the opinions of people who know more about Python
than I whether they think it would be
easy/hard/well-damn-nigh-impossible to add this kind of dynamic retyping
of objects based on predicates.
(I did a quick search on deja and didn't find any talk about this, so
apologies in advance if this is something that has been as talked to
death as the indentation thing.)
Sent via Deja.com http://www.deja.com/
Before you buy.
Good for you! I like Cecil a lot, too. You might also be interested in
Self (http://self.sunlabs.com) -- it implements dynamic inheritance,
which is one of the motivations for Chambers' invention of predicate
classes.
>I also thought it would be nifty if Python had them so I got the source
>from the CVS respository and started hacking the grammar and realized I
>had no idea what I was doing :-).
>
>Before getting in any deeper in something I only vaguely understand I
>thought I would ask the opinions of people who know more about Python
>than I whether they think it would be easy/hard/well-damn-nigh-impossible
>to add this kind of dynamic retyping of objects based on predicates.
Fortunately, you don't need to hack the Python source in order to
experiment with dynamic inheritance or predicate classes in Python,
because you can change a class's inheritance tree by assigning to a
class's __bases__ attribute at runtime.
Here's a quick, rather kludged-together example:
class Foo:
x = 4
class Bar:
predicate = 1
__bases__ = (Foo,)
#
def __setattr__(self, name, value):
if name == 'predicate':
self.__class__.predicate = value
if value:
self.__class__.__bases__ = (Foo,)
else:
self.__class__.__bases__ = ()
At the interpreter prompt:
>>> s = Bar()
>>> isinstance(s, Foo)
1
>>> s.x
4
>>> s.predicate = 0
>>> isinstance(s, Foo)
0
>>> s.x
Traceback (innermost last):
File "<stdin>", line 1, in ?
AttributeError: x
Whether or not s, the instance of Bar, inherited from Foo depends
on what the value of Bar.predicate was. Note that this isn't the
same thing as real predicate dispatch, yet, since different
instances of Foo can't have different virtual classes.
To make that work, you would need to create a custom sequence object
for your __bases__ object and hack together a metaclass to install it
cleanly. This isn't a simple project, but fortunately, it's not a big
job either -- most of the work is conceptual rather than writing reams
of code.
It will also be lots of fun; my current Python project right now is
writing a multimethod class for Python and I can vouch for the hack
value of something like this.
Some day in the future, *after* you have a good idea of what semantics
you want to implement, you can create a C extension type implementing
predicate classes and then extend the interpreter. But that's for
later; first prototype it in Python itself before wasting time writing
C code. Remember you won't know what the right thing is until you've
used your metaclass in a variety of projects, and you will feel much
easier about modifying and rewriting a Python class than a C
extension.
>(I did a quick search on deja and didn't find any talk about this, so
>apologies in advance if this is something that has been as talked to
>death as the indentation thing.)
Not at all! Cecil, Dylan and Self are all great languages to use to
discover Pythonic features in. :)
Neel
>At the interpreter prompt:
Ummm, not for me - with 1.5.2 from CVS I get:
>>> s = Bar()
>>> isinstance(s, Foo)
0
>>> s.__bases__
(<class __main__.Foo at 1400897f0>,)
>>> s.x
Traceback (innermost last):
File "<stdin>", line 1, in ?
AttributeError: x
>>> s
<__main__.Bar instance at 1400e19d0>
Mark
--
Email - ma...@chem.uwa.edu.au ,-_|\ Mark C Favas
Phone - +61 9 380 3482 / \ Department of Chemistry
Fax - +61 9 380 1005 ---> *_,-._/ The University of Western Australia
v Nedlands
Loc - 31.97 S, 115.81 E Western Australia 6009
Er, it looks like I made a booboo. Try this instead;
class Foo:
x = 4
class Bar:
def __init__(self):
self.__class__.predicate = 1
self.__class__.__bases__ = (Foo,)
def __setattr__(self, name, value):
if name == 'predicate':
self.__class__.predicate = value
if value:
self.__class__.__bases__ = (Foo,)
else:
self.__class__.__bases__ = ()
This works in my 1.5.2. The error appears to be that when __bases__ is
defined as a class initialization statement it gets stuffed into the
class __dict__ without updating the __bases__ attribute. (At least
that's what a cursory examination of classobject.c suggests.) Funky.
Neel