[python-nl] Problem passing instance (self) when calling CLIPS

Schneider f.schneider at de-bleek.demon.nl
Fri Dec 25 19:00:46 CET 2009


> On Fri, Dec 25, 2009 at 16:35, Frans Schneider
> <f.schneider at de-bleek.demon.nl> wrote:
> > No, asserting the fact and giving the CLIPS engine the run instructrion
> > will fire the rule which does the python-call to MyMethod. As you see
> > from the output, this works since the output shows 'MyMethod being
> > initialized'
> 
> Yeah, you're wrong here. The Callable.__init__ call happens at module
> load time, not at MyObject.MyMethod call time.
> 
Indeed, the decorator's __init__ is executed when the function is defined.
This will register the function in CLIPS and create the rule in CLIPS that
will be fired later when the fact is asserted. This is GOOD. It is the main
reason for me to use a decorator since it makes the code better readable.

I did solve the problem more or less by now by introducing weak references.
Why use weak references and not use hard references I am not sure yet, but
it works. The code now looks as follows.

import clips
import weakref

class Callable(object):

    def __init__(self, func):
        self._func = func
        clips.RegisterPythonFunction(func)
        r = clips.BuildRule("%s-rule" % func.__name__, 
                            "?f <- (duck ?instance_id)",
                            """(retract ?f) 
                            (python-call %s ?instance_id)""" %
func.__name__, 
                            "The %s rule" % func.__name__)
        print r.PPForm()
        print "%s being initialized" % self._func.__name__ 

    def __call__(self, *args, **kwargs):
        print "I am never executed"
        return self._func(*args, **kwargs)

class MyObject(object):
    
    def __init__(self, *args, **kwargs):
        super(MyObject, self).__init__(*args, **kwargs)
        try:
            MyObject._id2obj_dict
        except AttributeError:
            MyObject._id2obj_dict = weakref.WeakValueDictionary()
            MyObject._id2obj_dict[id(self)] = self
            
    @Callable
    def MyMethod(self):
        self = MyObject._id2obj_dict[self]
        print "I am being called by CLIPS with the arg", self
        print "The data is", self.data
        
    def Assert(self):
        self.data = "DATA"
        clips.Assert("(duck %s)" % id(self))

if __name__ == "__main__":
    clips.Reset()
    myObject = MyObject()
    myObject.Assert()
    clips.Run(100)
    print "Bye"

The output now looks like:

(defrule MAIN::MyMethod-rule "The MyMethod rule"
   ?f <- (duck ?instance_id)
   =>
   (retract ?f)
   (python-call MyMethod ?instance_id))

MyMethod being initialized
I am being called by CLIPS with the arg <__main__.MyObject object at
0x00BE6790>
The data is DATA
Bye

The thing I don't like is the line :

self = MyObject._id2obj_dict[self]

in MyMethod. Looks messy.

Frans



More information about the Python-nl mailing list