Возьмите список как объект
obj = []
list(filter(lambda x:callable(getattr(obj,x)),obj.__dir__()))
Вы получаете:
['__add__',
'__class__',
'__contains__',
'__delattr__',
'__delitem__',
'__dir__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__getitem__',
'__gt__',
'__iadd__',
'__imul__',
'__init__',
'__init_subclass__',
'__iter__',
'__le__',
'__len__',
'__lt__',
'__mul__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__reversed__',
'__rmul__',
'__setattr__',
'__setitem__',
'__sizeof__',
'__str__',
'__subclasshook__',
'append',
'clear',
'copy',
'count',
'extend',
'index',
'insert',
'pop',
'remove',
'reverse',
'sort']
Вы можете использовать макрос clojure.repl/source
, чтобы получить источник символа:
user> (source max)
(defn max
"Returns the greatest of the nums."
{:added "1.0"
:inline-arities >1?
:inline (nary-inline 'max)}
([x] x)
([x y] (. clojure.lang.Numbers (max x y)))
([x y & more]
(reduce1 max (max x y) more)))
nil
Но это только часть ответа. AFAICT source
ищет исходное имя файла и номер строки, которые определяют данный символ, а затем печатает исходный код из файла. Поэтому source
не будет работать с символами, для которых у вас нет источника, то есть с кодом компиляции AOT.
Возвращаясь к исходному вопросу, вы можете думать о source
как о чтении метаданных, связанных с данным символом, и просто распечатать их. То есть это обман. Это никоим образом не возвращает вам «код как данные», где с кодом я имею в виду скомпилированную функцию clojure.
На мой взгляд, «код как данные» относится к функции lisps, где исходный код эффективен структуру данных lisp, и, следовательно, ее можно прочитать считывающим устройством. То есть я могу создать структуру данных, которая является допустимым кодом lisp, и eval
, что.
Например:
user=> (eval '(+ 1 1))
2
Здесь '(+ 1 1)
- литеральный список, который читается читателем clojure, а затем оценивается как код clure.
Обновление: Yehonathan Sharvit спрашивал в одном из комментариев, если можно изменить код для функции. Следующий фрагмент читает в источнике для функции, изменяет результирующую структуру данных и, наконец, оценивает структуру данных, в результате чего определяется my-nth
новая функция:
(eval
(let [src (read-string (str (source-fn 'clojure.core/nth) "\n"))]
`(~(first src) my-nth ~@(nnext src))))
syntax-quote
строка заменяет nth
на my-nth
в форме defn
.
Вы можете получить исходный код в последних версиях clojure с функцией source
.
user=> (source nth)
(defn nth
"Returns the value at the index. get returns nil if index out of
bounds, nth throws an exception unless not-found is supplied. nth
also works for strings, Java arrays, regex Matchers and Lists, and,
in O(n) time, for sequences."
{:inline (fn [c i & nf] `(. clojure.lang.RT (nth ~c ~i ~@nf)))
:inline-arities #{2 3}
:added "1.0"}
([coll index] (. clojure.lang.RT (nth coll index)))
([coll index not-found] (. clojure.lang.RT (nth coll index not-found))))
nil
, чтобы получить строку как значение, которое вы можете обернуть в with-out-str
:
user=> (with-out-str (source nth))
"(defn nth\n \"Returns the value at the index. get returns nil if index out of\n bounds, nth throws an exception unless not-found is supplied. nth\n also works for strings, Java arrays, regex Matchers and Lists, and,\n in O(n) time, for sequences.\"\n {:inline (fn [c i & nf] `(. clojure.lang.RT (nth ~c ~i ~@nf)))\n :inline-arities #{2 3}\n :added \"1.0\"}\n ([coll index] (. clojure.lang.RT (nth coll index)))\n ([coll index not-found] (. clojure.lang.RT (nth coll index not-found))))\n"
user=>
Это было мое сообщение; приятно встретить вас ;-) Кстати, ссылки, приведенные в этой теме для ответов, были отличным чтением; поэтому, если вам интересно, вы можете потратить время на их чтение. Вернемся к вашему вопросу, хотя source
, похоже, работает для кода, загруженного через файл, но он не работает во всех случаях. Я думаю, в частности, он не работает для функций, определенных в repl.
user=> (def foo (fn [] (+ 2 2)))
#'user/foo
user=> (source foo)
Source not found
nil
user=> (defn foo2 [] (+ 2 2))
#'user/foo2
user=> (source foo2)
Source not found
nil
Копаем немного ...
user=> (source source)
(defmacro source
"Prints the source code for the given symbol, if it can find it.
This requires that the symbol resolve to a Var defined in a
namespace for which the .clj is in the classpath.
Example: (source filter)"
[n]
`(println (or (source-fn '~n) (str "Source not found"))))
nil
user=> (source clojure.repl/source-fn)
(defn source-fn
"Returns a string of the source code for the given symbol, if it can
find it. This requires that the symbol resolve to a Var defined in
a namespace for which the .clj is in the classpath. Returns nil if
it can't find the source. For most REPL usage, 'source' is more
convenient.
Example: (source-fn 'filter)"
[x]
(when-let [v (resolve x)]
(when-let [filepath (:file (meta v))]
(when-let [strm (.getResourceAsStream (RT/baseLoader) filepath)]
(with-open [rdr (LineNumberReader. (InputStreamReader. strm))]
(dotimes [_ (dec (:line (meta v)))] (.readLine rdr))
(let [text (StringBuilder.)
pbr (proxy [PushbackReader] [rdr]
(read [] (let [i (proxy-super read)]
(.append text (char i))
i)))]
(read (PushbackReader. pbr))
(str text)))))))
nil
Так что, похоже, он пытается загрузить исходный файл из класса, чтобы попытаться выплюнуть его для вас. Одна вещь, которую я узнал при работе с Clojure, - это то, что 9 раз из 10 полезно посмотреть на источник.