Páginas

domingo, 9 de novembro de 2008

A Neighborhood of Infinity: On writing Python one-liners.

Although most of my blog is in Portuguese, I knew somewhen I would start mixing languages and posting in English. So here it goes, my thoughts on one-liners...

Thanks to my academic advisor Carlo Emmanoel and his delicious, I was sent to a blog post [1] from sigfpe about Python one-liners.

Not that I really find it useful, but it's at least something interesting to play with. It's been a long time since I've first seen programmers challenging each other with mind breaking one-liners, usually trying to promote their favorite language.

The solution proposed by sigfpe make use of lambda forms, which, it seems, many people are not aware of -- as we can infer by the comments on the original post.
My approach to one-liners is way different.
Why tinker with lambdas when we can do it much simpler?

I'll show you how we can write ANY PYTHON CODE in only one line. Maybe you may argue that I have cheated, but it's pure core Python. Who cares about rules anyway?
The basic idea is to transform an arbitrary source-code into a single line string. Then, compile the string and exec it! I guess those two features of the language are also ignored by the majority of Python programmers.

So, let's do it to each example from the original post:
# we want to add 1 to all of the numbers from 0 to 19

def inc(n):
return n+1

print "1.",map(inc,range(0,20))

# sigfpe's solution using lambda forms...

print "1.",map(lambda x:x+1,range(0,20))

# My solution with exec & compile...

exec compile('def inc(n):\n return n+1\n\nprint "1.",map(inc,range(0,20))\n', '<string>', 'exec')
# Tricky idea on how to express local variables using lambdas

def f1(n):
m = 2*n+1
return m+m*m

print "2.",map(f1,range(0,20))

print "2.",map(lambda n:(lambda m:m+m*m)(2*n+1),range(0,20))

# Using exec & compile is inconvenient because it wastes too much space,
# since it keeps indentation whitespaces (that could be replaced by
# undesired \t's) and all the verbosity of multi-liners...

exec compile('def f1(n):\n m = 2*n+1\n return m+m*m\n\nprint "2.",map(f1,range(0,20))\n', '<string>', 'exec')
def f(n):
def g(n):
return 2*n+1

def h(n):
return 3*n-2

return g(h(g(h(n))))

print "3.",map(f,range(0,20))

print "3.",map(lambda n:(lambda g,h,n:g(h(g(h(n)))))(lambda n:2*n+1,lambda n:3*n-2,n),range(0,20))

# Also, note that the exec & compile method is "dumb", we are just writing
# multiline code in one line (escaping line breaks with \n), and calling
# our Python interpreter

exec compile('def f(n):\n def g(n):\n return 2*n+1\n\n def h(n):\n return 3*n-2\n\n return g(h(g(h(n))))\n\nprint "3.",map(f,range(0,20))\n', '<string>', 'exec')
def fact(n):
if n<=1:
return 1
else:
return n*fact(n-1)

print "4.",map(fact,range(0,20))

print "4.",map(lambda n:(lambda f:f(f,n))(lambda f,n:{True:lambda:1,False:lambda:n*f(f,n-1)}[n<=1]()),range(0,20))

# In practice, there's no difference between the code written in multiple lines
# and my naive approach to one-liners. There may be problems trying to run
# lengthier code, where that trivial solution won't work.

exec compile('def fact(n):\n if n<=1:\n return 1\n else:\n return n*fact(n-1)\n\nprint "4.",map(fact,range(0,20))\n', '<string>', 'exec')

The process is so mechanical and immediate that I've written a short script:
'''
onelify.py :: Transform arbitrary Python code into an one-liner equivalent.

2008/11/09 - Initial release

Rodolfo Henrique Carvalho :: lifeatmymind.blogspot.com
'''

def onelinefy(code):
return "exec compile(%s, '<string>', 'exec')" % (repr(code),)

[1] A Neighborhood of Infinity: On writing Python one-liners.

UPDATE: 2008/12/26 - Now using Google Code Prettifier for syntax coloring!

2 comentários:

rkaiser disse...
Este comentário foi removido pelo autor.
lucastx disse...

Cheaaaater >D

Mas hein, aqui uma coisa q deve ser interessante pra vc, sobre oneliners:

http://www.ricbit.com/2008/05/python-one-liners-so-turing-complete.html