@@ -75,7 +75,7 @@ INFO: Reference thread starting
7575
7676This dynamically finds the python shared library and loads it using output from
7777the python3 executable on your system. For information about how that works,
78- please checkout the code
78+ please checkout the code
7979[ here] ( https://github.com/cnuernber/libpython-clj/blob/master/src/libpython_clj/python/interpreter.clj#L30 ) .
8080
8181
@@ -308,36 +308,36 @@ user> (py/$.. numpy random shuffle)
308308
309309##### New sugar (fixme )
310310
311- `libpython-clj` offers syntactic forms similar to those offered by
312- Clojure for interacting with Python classes and objects.
311+ `libpython-clj` offers syntactic forms similar to those offered by
312+ Clojure for interacting with Python classes and objects.
313313
314314**Class/object methods**
315315Where in Clojure you would use `(. obj method arg1 arg2 ... argN)`,
316- you can use `(py. pyobj method arg1 arg2 ... argN)`.
316+ you can use `(py. pyobj method arg1 arg2 ... argN)`.
317317
318318In Python, this is equivalent to `pyobj.method(arg1, arg2, ..., argN)`.
319319Concrete examples are shown below.
320320
321321**Class/object attributes**
322- Where in Clojure you would use `(.- obj attr)`, you can use
322+ Where in Clojure you would use `(.- obj attr)`, you can use
323323`(py.- pyobj attr)`.
324324
325- In Python, this is equivalent to `pyobj.attr`.
325+ In Python, this is equivalent to `pyobj.attr`.
326326Concrete examples shown below.
327327
328328**Nested attribute access**
329329To achieve a chain of method/attribute access, use the `py..` for.
330330
331- ```clojure
332- (py.. (requests/get " http://www.google.com" )
331+ ```clojure
332+ (py.. (requests/get " http://www.google.com" )
333333 -content
334334 (decode " latin-1" ))
335335```
336336(**Note**: requires Python `requests` module installled)
337337
338338**Examples**
339339
340- ```clojure
340+ ```clojure
341341user=> (require '[libpython-clj.python :as py :refer [py. py.. py.-]])
342342nil
343343user=> (require '[libpython-clj.require :refer [require-python]])
@@ -418,3 +418,79 @@ please refer to the datatype library [documentation](https://github.com/techasce
418418
419419Just keep in mind, careless usage of zero copy is going to cause spooky action at a
420420 distance.
421+
422+
423+ ### Pickle
424+
425+ Speaking of numpy, you can pickle python objects and transform the result via numpy and dtype
426+ to a java byte array and back:
427+
428+
429+ ```clojure
430+ user> (require '[libpython-clj2.python :as py])
431+ nil
432+ user> (py/initialize! )
433+ Sep 03 , 2022 11 :23 :34 AM clojure.tools.logging$eval5948$fn__5951 invoke
434+ INFO: Detecting startup info
435+ Sep 03 , 2022 11 :23 :34 AM clojure.tools.logging$eval5948$fn__5951 invoke
436+ INFO: Startup info {:lib-version " 3.9" , :java-library-path-addendum " /home/chrisn/miniconda3/lib" , :exec-prefix " /home/chrisn/miniconda3" , :executable " /home/chrisn/miniconda3/bin/python3" , :libnames ("python3.9m" " python3.9" ), :prefix " /home/chrisn/miniconda3" , :base-prefix " /home/chrisn/miniconda3" , :libname " python3.9m" , :base-exec-prefix " /home/chrisn/miniconda3" , :python-home " /home/chrisn/miniconda3" , :version [3 9 1 ], :platform " linux" }
437+ Sep 03 , 2022 11 :23 :34 AM clojure.tools.logging$eval5948$fn__5951 invoke
438+ INFO: Prefixing java library path: /home/chrisn/miniconda3/lib
439+ Sep 03 , 2022 11 :23 :35 AM clojure.tools.logging$eval5948$fn__5951 invoke
440+ INFO: Loading python library: python3.9
441+ Sep 03 , 2022 11 :23 :35 AM clojure.tools.logging$eval5948$fn__5951 invoke
442+ INFO: Reference thread starting
443+ :ok
444+ user> (def data (py/->python {:a 1 :b 2 }))
445+ #'user/data
446+ user> (def pickle (py/import-module " pickle" ))
447+ #'user/pickle
448+ user> (def bdata (py/py. pickle dumps data))
449+ #'user/bdata
450+ user> bdata
451+ b'\x80\x04\x95\x11\x00\x00\x00\x00\x00\x00\x00}\x94(\x8c\x01a\x94K\x01\x8c\x01b\x94K\x02u.'
452+ user> (def np (py/import-module " numpy" ))
453+ #'user/np
454+ user> (py/py. np frombuffer bdata :dtype " int8" )
455+ [-128 4 -107 17 0 0 0 0 0 0 0 125 -108 40
456+ -116 1 97 -108 75 1 -116 1 98 -108 75 2 117 46 ]
457+ user> (require '[libpython-clj2.python.np-array])
458+ nil
459+ user> (def ary (py/py. np frombuffer bdata :dtype " int8" ))
460+ #'user/ary
461+ user> (py/->jvm ary)
462+ #tech.v3.tensor<int8>[28 ]
463+ [-128 4 -107 17 0 0 0 0 0 0 0 125 -108 40 -116 1 97 -108 75 1 -116 1 98 -108 75 2 117 46 ]
464+ user> (require '[tech.v3.datatype :as dt])
465+ nil
466+ user> (dt/->byte-array *2)
467+ [-128 , 4 , -107 , 17 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 125 , -108 , 40 , -116 , 1 , 97 , -108 , 75 , 1 ,
468+ -116 , 1 , 98 , -108 , 75 , 2 , 117 , 46 ]
469+ user> (require '[tech.v3.tensor :as dtt])
470+ nil
471+ user> (dtt/as-tensor *2)
472+ nil
473+ user> (def bdata *3 )
474+ #'user/bdata
475+ user> bdata
476+ [-128 , 4 , -107 , 17 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 125 , -108 , 40 , -116 , 1 , 97 , -108 , 75 , 1 ,
477+ -116 , 1 , 98 , -108 , 75 , 2 , 117 , 46 ]
478+ user> (type bdata)
479+ [B
480+ user> (def tens (dtt/reshape bdata [(dt/ecount bdata)]))
481+ #'user/tens
482+ user> (def pdata (py/->python tens))
483+ #'user/pdata
484+ user> pdata
485+ [-128 4 -107 17 0 0 0 0 0 0 0 125 -108 40
486+ -116 1 97 -108 75 1 -116 1 98 -108 75 2 117 46 ]
487+ user> (py/python-type *1)
488+ :ndarray
489+ user> (def py-ary *2 )
490+ #'user/py-ary
491+ user> (def py-bytes (py/py. py-ary tobytes))
492+ #'user/py-bytes
493+ user> (py/py. pickle loads py-bytes)
494+ {'a': 1 , 'b': 2 }
495+ user>
496+ ```
0 commit comments