I recently touched Clojure for some reason.
For those who have been using procedural languages such as C and Python for nearly eight years, at first there was some confusion about "functional languages", but on the other hand, Python incorporates many of the advantages of functional languages. I also noticed.
Therefore, I would like to try out how much functional language-like things can be done with Python by referring to Clojure's sample.
This time, ayato-p published "Clojure's Japanese Guide" Idioms Let's implement the contents of /clojure-beginner/idioms/index.html) in Python. The version of Python at hand is 3.6.1.
[0 1 2 3 4]
[:a :b :c :d :e]
There is no "keyword" in Python, so use a string instead. It's easy with zip.
a = [0, 1, 2, 3, 4]
b = [":a" ":b" ":c" ":d" ":e"]
zip(a, b)
# -> <zip at 0x111a14548>
Oops, Python 3 makes heavy use of iterators. It is not evaluated as it is, so if you want to see each element, you need to enclose it in a list.
list(zip(a, b))
# -> [(0, ':a'), (1, ':b'), (2, ':c'), (3, ':d'), (4, ':e')]
{:name "ayato-p"
:age "24"
:address "Japan"}
Concatenate (key, value) pairs in the dictionary using the chain in the itertools module. The asterisk "*" is an operator for passing list elements as function arguments.
import itertools
d = {":name": "ayato-p",
":age": "24",
":address": "Japan"}
list(itertools.chain(*d.items()))
# -> [':name', 'ayato-p', ':age', '24', ':address', 'Japan']
(def v ["foo" "bar" "baz"])
(defn f [& args]
(clojure.string/join ", " args))
The way to pass arguments is the same as we did above. You also use an asterisk to define a function that accepts variadic arguments.
v = ["foo", "bar", "baz"]
def f(*args):
return ", ".join(args)
f(*v)
# -> 'foo, bar, baz'
When passing a dictionary, use two asterisks.
m = {"name": "ayato-p", "age": 24}
def g(name, age):
return "name:" + name + ", age:" + str(age)
g(**m)
# -> 'name:ayato-p, age:24'
(def people [{:name "ayato_p" :age 11}
{:name "alea12" :age 10}
{:name "zer0_u"}])
(remove nil? (map :age people)) ;(11 10)
(keep :age people) ;(11 10)
Just use the list comprehension with the conditional expression.
people = [{":name": "ayato_p", ":age": 11},
{":name": "alea12", ":age": 10},
{":name": "zer0_u"}]
[x[":age"] for x in people if ":age" in x]
# -> [11, 10]
Use is instance.
isinstance(True, bool) # -> True
isinstance(False, bool) # -> True
isinstance("", bool) # -> False
isinstance(None, bool) # -> False
isinstance(0, bool) # -> False
isinstance(1, bool) # -> False
This is the same for Clojure and Python.
None or "ayato-p"
# -> "ayato-p"
However, everything that becomes False when booled (None, 0, False, empty list, etc.) applies, so I think it is better to use if seriously.
You can measure the length with len or evaluate it with if as it is. If you enclose it in bool, True / False will be returned depending on the presence or absence of the contents.
ev = []
v = [1, 2]
if ev:
print("not empty")
else:
print("empty")
# -> empty
if v:
print("not empty")
else:
print("empty")
# -> not empty
bool(ev)
# -> False
bool(v)
# -> True
(def m {:foo 1 :bar 2})
(cond-> m
true (assoc :baz 3)) ;{:foo 1, :bar 2, :baz 3}
(cond-> m
false (assoc :baz 3)) ;{:foo 1, :bar 2}
using if and dict
m = {":foo": 1, ":bar": 2}
dict(m, **{":baz": 3}) if True else m
# -> {':bar': 2, ':baz': 3, ':foo': 1}
dict(m, **{":baz": 3}) if False else m
# -> {':bar': 2, ':foo': 1}
This is the first time I've used the dict function in this way. When actually writing a program in Python, I think that it is more common to rewrite the contents of dict before using it.
(reduce (fn [acc x]
(if (zero? x)
(reduced 0)
(* acc x)))
1
(cycle [9 8 7 6 5 4 3 2 1 0]))
Since reduced is not in Python, we use exceptions to implement similar functionality.
import functools
class Reduced(Exception):
def __init__(self, data):
super().__init__()
self.data = data
def myreduce(f, it):
try:
return functools.reduce(f, it)
except Reduced as e:
return e.data
def mymultiply(acc, x):
if x == 0:
raise Reduced(0)
return acc * x
myreduce(mymultiply, [9, 8, 7, 6, 5, 4, 3, 2, 1, 0])
# -> 0
Easy with dictionary comprehension.
m = {"key1": 1,
"key2": 2,
"key3": 3}
{":" + k: v for k, v in m.items()}
# -> {':key1': 1, ':key2': 2, ':key3': 3}
If you want to change the data in the list, you can use pop. You can also create a new list using enumerate and list comprehensions.
l = [9, 8, 7, 6, 5, 4, 3, 2, 1]
l.pop(5)
l
# -> [9, 8, 7, 6, 5, 3, 2, 1]
l = [9, 8, 7, 6, 5, 4, 3, 2, 1]
[x for i, x in enumerate(l) if i != 5]
# -> [9, 8, 7, 6, 5, 3, 2, 1]
Ordinary Python cannot handle Java instances. There seems to be Python implemented in Java called Jython, but it seems that development is stagnant, so skip it.
This is usually a for loop.
Skip it because the quote source says "I don't recommend it very much".
(filter identity [nil false true 1 "hello" [1 2] {:foo 1} :hoge])
;; (true 1 "hello" [1 2] {:foo 1} :hoge)
This is also a list comprehension
[x for x in [None, False, True, 1, "hello", [1, 2], {":foo": 1}] if x]
# -> [True, 1, 'hello', [1, 2], {':foo': 1}]
As already mentioned above, we will use enumerate.
list(enumerate(["a", "b", "c", "d", "e"]))
# -> [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd'), (4, 'e')]
By doing this, you can use it as follows.
[str(i) + " is " + x for i, x in enumerate(["a", "b", "c", "d", "e"])]
# -> ['0 is a', '1 is b', '2 is c', '3 is d', '4 is e']
(defn find-first [pred coll]
(first (drop-while (complement pred) coll)))
It seems like you should write a sloppy for loop, but I won't write it! !! Create a generator and use next to retrieve the first element.
l = [1, 2, 3, 4, 5, 6, 7, 8, 9]
next(x for x in l if x > 4)
# -> 5
An example of extracting the smallest prime number larger than a certain natural number by trial division
import itertools
def isprime(x):
return next((0 for n in range(2, int(x ** 0.5) + 1)
if x % n == 0), 1)
next(x for x in itertools.count(1000) if isprime(x))
# -> 1009
(Added on July 20, 2017) In primality test, it is more concise to use "all" which returns true when all elements of iterable are true.
def isprime(x):
return all(x % n for n in range(2, int(x ** 0.5) + 1))
Could you give us a quick comparison between Clojure and Python? I'm new to Clojure, so there may be a lot of things that Clojure can and Python can't.
However, if you look at it like this, you can see that in Python, by using list comprehensions and generator expressions, it is possible to write functional language-like processing very compactly without writing extra function names.
You don't have to force yourself to use the generator as in the last example, but if you look at it to the extent that you can do something like this, it may help you write code someday.
See you soon~.
Recommended Posts