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!
Recent Comments