This lib adds some anti-Pythonic "syntactic sugar" to Python.
NOTE: This is merely an experimental prototype to show some potential of operator overloading in Python. Only tested under Python 3.6.0. Anything may evolve without announcement in advance.
Inspired by https://github.com/matz/streem.
Also, you can watch the last part of this Matz's talk to understand the intuition behind this project.
pip install syntax_sugar
To test out this lib, you can simply do.
fromsyntax_sugarimport*For serious use, you can explicitly import each component as explained below ... if you dare to use this lib.
fromsyntax_sugarimportpipe, ENDfromfunctoolsimportpartialpipe(10) |range|partial(map, lambdax: x**2) |list|print|END# put 10 into the pipe and just let data flow.# output: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]# remember to call END at the end# NOTE: everything in the middle of the pipe is just normal Python functionspipe(10) |range| (map, lambdax: x**2) |list|print|END# Tuples are shortcuts for partial functionsfromsyntax_sugarimporteachx=pipe(10) |range|each(lambdax: x**2) |END# We can also save the result in a variable.# `each` is an eager evaluated version of the partial function of `map`, which returns a list instead of a map object. (Equivalent to `map` in Python 2)pipe(10) |range|each(str) |''.join>'test.txt'# wanna write to a file? Why not!# write "0123456789" to test.txt# We don't need to put END here.We can connect multiple pipes to create a longer pipe
fromsyntax_sugarimportpipe, each, ENDfromfunctoolsimportreducep1=pipe(10) |range|each(lambdax: x/2)
# head pipe can have input valuep2=pipe() | (reduce, lambdaacc, x: (acc+x)/2)
p3=pipe() |int|range|sum# middle pipes can have no input valuep1|p2|p3|END# returns 6p=p1|p2|p3p()
# You can invoke the pipe by calling it as a function# you can also put a different value in the pipep(20)
# returns 36By default, pipe works with threads.
You can have a function running in a seperate thread with pipe. Just put it in a [] or more explicitly t[]. Threads and processes are also available.
fromsyntax_sugarimport (thread_syntaxast,
process_syntaxasp)
pipe(10) | [print] |END# print run in a threadpipe(10) |t[print] |END# print run in a threadpipe(10) |p[print] |END# print run in a processWhat makes this syntax good is that you can specify how many threads you want to spawn, by doing [function] * n where n is the number of threads.
pipe([1,2,3,4,5]) | [print] *3|END# print will run in a ThreadPool of size 3Here is an example of requesting a list of urls in parallel
importrequests
(pipe(['google', 'twitter', 'yahoo', 'facebook', 'github'])
|each(lambdaname: 'http://'+name+'.com')
| [requests.get] *3# !! `requests.get` runs in a ThreadPool of size 3|each(lambdaresp: (resp.url, resp.headers.get('Server')))
|list|END)
# returns# [('http://www.google.com/', 'gws'),# ('https://twitter.com/', 'tsa_a'),# ('https://www.yahoo.com/', 'ATS'),# ('https://www.facebook.com/', None),# ('https://github.com/', 'GitHub.com')]fromsyntax_sugarimportis_a, has, to, step, drop1/is_a/int# equivalent to `isinstance(1, int)`1/as_a/str# "1"range(10) /has/'__iter__'# equivalent to `hasattr(range(10), "__iter__")`1/to/10# An iterator similar to `range(1, 11)`.# Python's nasty range() is right-exclusive. This is right-inclusive.10/to/1# We can go backward.'0'/to/'9'# We can also have a range of characters :)1/to/10/step/2# We can also specify step sizes.# Similar to `range(1, 11, 2)`10/to/1/step/2# Go backward.# Similar to `range(10, 0, -2)`1/to/10/drop/5# there is a `drop` functon which drop N items from the head# An iterator similar to [6, 7, 8, 9, 10]/to/ has some advanced features
- lazy evaluation.
- support infinity.
- support product operation.
- support pipe.
fromsyntax_sugarimportINF, take, each# CAUTION: this will infinitely print numbersforiin1/to/INF:
print(i)
1/to/INF/take/5/as_a/list# there is a `take` functon which is similar to itertools.islice# return [1, 2, 3, 4, 5]1/to/ ... /take/5/as_a/list# ... is equivalent to INF0/to/-INF/step/2/take/5/as_a/list# also works with negative infinity.# return [0, -2, -4, -6, -8]
(1/to/3) * (4/to/6) /as_a/list# all combinations of [1..3] * [4..6]# return [(1, 4), (1, 5), (1, 6), (2, 4), (2, 5), (2, 6), (3, 4), (3, 5), (3, 6)]1/to/10/take/5|each(lambdax: x**2) |END# These infix functions can also be piped.# [1, 4, 9, 16, 25]Make your own infix function, so you can append multiple items to a list in one line.
fromsyntax_sugarimportinfix@infixdefpush(lst, x):
lst.append(x)
returnlst
[] /push/1/push/2/push/3# returns [1,2,3]You can also do
defpush(lst, x):
lst.append(x)
returnlstipush=push/as_a/infix
[] /ipush/1/ipush/2/ipush/3# returns [1,2,3]In math, (f * g) (x) = f(g(x)). This is called function composition.
# lmap equivalent to `list(map(...))`lmap=compose(list, map)
lmap(lambdax: x**2, range(10))Let's say we want to represent f * g * h in a program, i.e. fn(x) = f(g(h(x)))
f=lambdax: x**2+1g=lambdax: 2*x-1h=lambdax: -2*x**3+3fn=compose(f, g, h)
fn(5) # 245026or you can do
f=composable(lambdax: x**2+1)
g=composable(lambdax: 2*x-1)
h=composable(lambdax: -2*x**3+3)
fn=f*g*hfn(5) # 245026Sometimes you may prefer the decorator way.
# make your own composable functions@composabledefadd2(x):
returnx+2@composabledefmul3(x):
returnx*3@composabledefpow2(x):
returnx**2fn=add2*mul3*pow2# equivalent to `add2(mul3(pow2(n)))`fn(5)
# returns 5^2 * 3 + 2 = 77More receipes: https://github.com/czheo/syntax_sugar_python/tree/master/recipes
