Как я могу получить доступ к слоту неизвестного экземпляра, используя строку?
проблема
Учитывая пример, inst
и строка attr
содержащий имя слота, как я могу получить значение слота attr
на inst
?
Конечно, если attr
были бы символом, а не строкой, я бы просто использовал (slot-value inst attr)
, но, кажется, мне нужна информация о пакете, чтобы правильно позвонить intern
(увидеть ниже).
Минимальный пример
(defpackage :pack1
(:use :common-lisp)
(:export :*inst*))
(in-package :pack1)
(defclass temp-class ()
((temp-slot :initarg :temp-slot)))
(defvar *inst* (make-instance 'temp-class :temp-slot "value"))
(defpackage :pack2
(:use :common-lisp :pack1)
(:import-from :pack1 :temp-class))
(in-package :pack2)
(let ((inst *inst*) ; In the real example, inst gets defined outside my control,
; in yet another package
(attr "temp-slot"))
(format t "Given package name: ~S; " ; prints fine
(slot-value inst (intern (string-upcase attr) :pack1)))
(format t "No package name: ~S; " ; signals an error
(slot-value inst (intern (string-upcase attr)))))
Предшествующий уровень техники
- Из этого вопроса я понял, что моя проблема была в том, что
intern
создавал символы в пакете, отличном от того, в котором был определен класс. - Из этого вопроса видно, что я не могу извлечь информацию о пакете просто из экземпляра, поэтому мне придется найти другой способ (помимо использования
intern
попасть туда)
Фон
Я работаю на py-format
Общий Лисп порт Python {}
-formatting. Для реализации Python .
оператор (getattr
) Мне нужно преобразовать строку после точки в слот на объекте, предшествующем точке.
1 ответ
Учитывая экземпляр, inst и строку attr, содержащую имя слота, как я могу получить значение attr слота для inst?
Слоты имеют не строки как имена слотов, а символы. Поскольку имена слотов могут быть произвольными символами, не существует общего способа получить значение слота, если у вас есть только строка.
CL-USER 124 > (defclass foo ()
((s) ; the slot-name is cl-user::s
(system::s) ; the slot-name is system::s
(#:s))) ; the slot-name is #:s
#<STANDARD-CLASS FOO 413054236B>
Последний слот-имя является непостоянным символом. Это не в упаковке. Таким образом, вы не можете найти его в любом случае, если вы не сохранили его где-то.
CL-USER 125 > (make-instance 'foo)
#<FOO 402013F043>
CL-USER 126 > (describe *)
#<FOO 402013F043> is a FOO
S #<unbound slot>
S #<unbound slot>
S #<unbound slot>
Как вы видите выше, у него есть три слота. Каждый символ имеет название s
, но это действительно другой символ.
Вы можете получить имена слотов через самоанализ:
CL-USER 127 > (mapcar #'slot-definition-name
(class-direct-slots (find-class 'foo)))
(S SYSTEM::S #:S)
Для переносимых функций см. CLOSER-MOP.