CLPython: Python in Common Lisp – Part 2

Written by on July 22, 2017 in LISP, Programming, Python with 0 Comments

We looked at the basic features of CLPython in our last blog. In today’s post let us look at the support for Python classes.

PYTEST 130 > (defun pyclass ()

  (run 

“class Employee:

   def __init__(self, name, dept):

     self.name = name

     self.dept = dept

   def dump(self):

     print ‘Name = ‘, self.name, ‘, Dept = ‘, self.dept

   def setDept(self, dept):

     self.dept = dept

“))

PYCLASS

PYTEST 131 > (setf cls (pyclass))

#<class Employee 40202F63AB>

We have now defined a Python class (called Employee) on the fly. The variable cls stores the Lisp representation of the class.

One way to create an instance of this class is execute a corresponding Python command in Lisp:

PYTEST 132 > (setf obj (run “x = Employee(‘John’, ‘Sales’)”))

#<Employee 402008052B>

As you can guess, x is a Python variable and obj is a Lisp variable, both referencing the same Employee object. Another way is to create the instance directly in Lisp using the CLPython function py-call:

PYTEST 133 > (setf obj2 (py-call cls “Mary” “HR”))

#<Employee 40200932F3>

Note that in both cases, we have to supply the constructor arguments.

We can invoke the dump method and see the the values of the instance varables:

PYTEST 134 > (run “x.dump()”)

Name =  John , Dept =  Sales

None

What about accessing the methods through the Lisp object? Unfortunately, I could not find a way to do this.

The documentation says that Python class is mapped to CLOS class and instance is mapped to CLOS instance. So I decided to introspect the class/object using methods in the CLOS Meta Object Protocol (MOP).

PYTEST 135 > (class-slots cls)

(#<STANDARD-EFFECTIVE-SLOT-DEFINITION CLPYTHON::DICT 4020155263>)

PYTEST 136 > (mapcar #’slot-definition-name (class-slots cls))

(CLPYTHON::DICT)

It appears as if there is just one slot called DICT in the corresponding Lisp class. We can retrieve its values thus:

PYTEST 137 > (slot-value obj ‘CLPYTHON::dict)

((CLPYTHON.USER::|dept| . “Sales”) (CLPYTHON.USER::|name| . “John”))

So the various instance variables and values are stored as cons pairs in this single slot.

OK, can we change the vaue of the field directly via the slot?

PYTEST 138 > (setf (first (slot-value obj ‘CLPYTHON::dict)) ‘(CLPYTHON.USER::|dept| . “PR”))

(CLPYTHON.USER::|dept| . “PR”)

PYTEST 139 > (run “x.dump()”)

Name =  John , Dept =  PR

None

OK, that is nice!

We can change the dept by invoking the instance method as well:

PYTEST 140 > (run “x.setDept(‘Mktg’)”)

None

PYTEST 141 > (run “x.dump()”)

Name =  John , Dept =  Mktg

None

This is confirmed via the other Lispy check:

PYTEST 142 > (slot-value obj ‘CLPYTHON::dict)

((CLPYTHON.USER::|dept| . “Mktg”) (CLPYTHON.USER::|name| . “John”))

One thing that is apparent from my investigation is that the mapping from Python class to Lisp class is not exact. What I mean is that Python class is not mapped to Lisp class with the fields being mapped to slots and methods to defmethods. Maybe there was a reason to do it this way. That is perfectly understandable.

Well, that concludes my brief study of CLPython. Have a great day!

Tags: , , ,

Subscribe

If you enjoyed this article, subscribe now to receive more just like it.

Subscribe via RSS Feed

Leave a Reply

Your email address will not be published. Required fields are marked *

Top