clj
clj is a collection of functions to work with lazy iterators in Python.
It’s a module for those times when you did too much Clojure and came back to Python wondering where are all these
distinct, drop-while, cycle, first, etc.
The library is oriented toward laziness and performance. Functions are implemented with as little overhead as possible.
Install
pip install clj
Python requirement:
- 0.4.x: Python 3.9+
- 0.3.x: Python 3.7+
- 0.2.x: Python 3.7+
- 0.1.x: Python 2.7, 3.3+
Usage
The library is considered stable and is used in production.
Example
;; Clojure
(->> coll (map inc) (filter even?) distinct count println)
; which expands to:
(println (count (distinct (filter even? (map inc coll)))))
# Python
from clj import count, distinct, inc, is_even
print(count(distinct(filter(is_even, map(inc, coll)))))
Note that count() works on both sequences in generators; in the latter case it doesn’t load everything in memory like
e.g. len(list(g)) would do.
Core Ideas
- Lazy by default. All functions should work on arbitrary iterators and return generators.
- This is Python. We keep Python’s semantics instead of trying to reproduce Clojure in Python (e.g.
0and[]are logically true in Clojure but false in Python;Noneis not equivalent to an empty collection). - Don’t Reinvent the Wheel. We don’t reimplement built-in functions unless they miss something, like
rangethat can’t be called without argument to yield an infinite sequence.
Support
The general naming scheme is: use underscores instead of hyphens; start the function with is_ if its Clojure
counterparts ends with a ?.
Sequences
We aim to implement all Clojure functions that operate on sequences (see the list here). They all work on iterables and return generators by default (Python’s closest equivalent of lazy seqs). We don’t support transducers.
| Clojure | clj |
Comment |
|---|---|---|
distinct |
distinct |
|
filter |
filter |
Alias to Python’s built-in filter. |
remove |
remove |
|
keep |
keep |
|
keep-indexed |
keep_indexed |
|
cons |
cons |
|
concat |
concat |
Equivalent to itertools.chain. |
lazy-cat |
- | Use Python’s itertools.chain. |
mapcat |
mapcat |
|
cycle |
cycle |
|
interleave |
interleave |
|
interpose |
interpose |
|
rest |
rest |
|
next |
- | Use rest. |
fnext |
- | Use second. |
nnext |
- | Use rest(rest(…)) |
drop |
drop |
|
drop-while |
drop_while |
Equivalent to itertools.dropwhile. |
nthnext |
- | Use drop. |
take |
take |
|
take-nth |
take_nth |
|
take-while |
take_while |
Equivalent to itertools.takewhile. |
butlast |
butlast |
|
drop-last |
drop_last |
|
flatten |
flatten |
|
reverse |
reverse |
|
sort |
- | Use Python’s built-in sort. |
sort-by |
- | Use sort(…, key=your_function). |
shuffle |
shuffle |
|
split-at |
split_at |
|
split-with |
split_with |
|
partition |
partition |
(partition n step pad coll) becomes partition(coll, n, step, pad). Only the case step=n is supported for now. |
partition-all |
||
partition-by |
partition_by |
|
map |
map |
Alias to Python’s built-in map. |
pmap |
- | |
replace |
replace |
|
reductions |
reductions |
(reductions f i c) becomes reductions(f, c, i). |
map-indexed |
map_indexed |
|
seque |
- | |
first |
first |
None is not a valid parameter. |
ffirst |
ffirst |
None is not a valid parameter. |
nfirst |
nfirst |
|
second |
second |
|
nth |
nth |
|
last |
last |
|
rand-nth |
- | Use Python’s random.choice. |
zipmap |
zipmap |
|
into |
- | |
reduce |
- | Use Python’s functools.reduce. |
set |
- | Use Python’s set. |
vec |
- | Use Python’s list. |
into-array |
- | Use Python’s list. |
to-array-2d |
- | |
frequencies |
- | Use Python’s collections.Counter. |
group-by |
group_by |
|
apply |
- | Use the f(*args) construct. |
not-empty |
- | |
some |
some |
|
seq? |
is_seq |
|
every? |
every |
|
not-every? |
not_every |
|
not-any? |
not_any |
|
empty? |
- | |
empty |
empty |
|
doseq |
- | Use for … in. |
dorun |
dorun |
|
doall |
- | Use Python’s list. |
realized? |
- | |
seq |
- | Use Python’s list. |
vals |
- | Use Python’s dict.values. |
keys |
- | Use Python’s dict.keys. |
rseq |
- | |
subseq |
- | |
rsubseq |
- | |
repeatedly |
repeatedly |
|
iterate |
iterate |
|
repeat |
repeat |
(repeat n x) becomes repeat(x, n). Equivalent to itertools.repeat. |
range |
range |
Prefer Python’s range for everything but infinite generators. |
line-seq |
- | Loop over an io.BufferedReader. |
resultset-seq |
- | |
re-seq |
- | Use Python’s re.finditer. |
tree-seq |
tree_seq |
|
file-seq |
- | Use Python’s os.walk. |
xml-seq |
- | |
iterator-seq |
- | |
enumeration-seq |
- | |
hash-map |
- | Use Python’s dict. |
array-map |
- | Use Python’s dict. |
sorted-map |
- | Use collections.OrderedDict. |
sorted-map-by |
- | |
hash-set |
- | Use Python’s set. |
set |
- | Use Python’s set. |
sorted-set |
- | |
sorted-set-by |
- | |
dedupe |
dedupe |
We also implemented count, which uses Python’s len when possible and fallbacks on a for loop for other cases.
Functions
We also provide miscellaneous functions as well as functions that work on functions.
| Clojure | clj |
Comment |
|---|---|---|
identity |
identity |
|
partial |
- | Use Python’s functools.partial |
comp |
comp |
|
complement |
complement |
|
constantly |
constantly |
|
juxt |
juxt |
|
distinct? |
is_distinct |
| Clojure | clj |
Comment |
|---|---|---|
inc |
inc |
|
dec |
dec |
Metadata
Release files for clj 0.5.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| clj-0.5.0.tar.gz | 13.5 kB | Without provenance | Details for clj-0.5.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| clj-0.5.0-py3-none-any.whl | Python 3 | none | any | Details for clj-0.5.0-py3-none-any.whl |
Total release size: 25.9 kB
Release files / clj-0.5.0.tar.gz
| Download URL | clj-0.5.0.tar.gz |
|---|---|
| Size | 13.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
fa33a63b71b42cf99a25dbe7663ad73c2f2a1dcdd5640e163dd97cc604e1882e
|
|
BLAKE2b-256 checksum How to use checksums |
0c4ab9c7560a79edaeb80d7c06c9dfdce56dc0e9a85fc7fbc05d1e132fdbde96
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/2.1.3 CPython/3.9.21 Linux/6.11.0-1015-azure
|
Release files / clj-0.5.0-py3-none-any.whl
| Download URL | clj-0.5.0-py3-none-any.whl |
|---|---|
| Size | 12.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5d8e7abd8d3ff4d5f82bd02c17f8741a34d63fe77d05772c760f2db4f0cf49b9
|
|
BLAKE2b-256 checksum How to use checksums |
181f3cba799b4a90bf5d8149066b8cc676c3a9d9712a1b1c0bda8c81ec0d02c0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/2.1.3 CPython/3.9.21 Linux/6.11.0-1015-azure
|
Security for clj 0.5.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.