「」に属する記事(最新5件のみ展開表示)

メイン

2006年09月25日

How to make oneliner in Python?

One day I fought on a boxing ring using my Thinkpad. It is a festival for nerds who loves lightweight language. (See Boxing in the LLRing?) My session was "Janken2.0", to make program to connect a server and play "Paper-Scissors-Rock". This entry is a FAQ, notFrequently Asked Question to make Python oneliner.

Is it difficult to make oneliners in Python?

You should learn Python more. Python use an indentation as a block. But what is the indentation? It is white region after "new line". No "new line" means no block, that is the most of syntax is disabled.

Is it impossible to make oneliners in Python?

No. See this. This is the "Paper-Scissors-Rock" agent.

jankenoneliner.png

How can I write "if" statement in a line?

"if" statement requires new line.

if condition:[new line]
    then-clause[new line]

if condition: then-clause[new line]

So, you can't use "if". Use "and" and "or".

condition and then-clause or else-clause

The right operand of "and" and "or" is evaluated lazily. But notice, if "bool(then-clause)" is False it doesn't work as you expected. You can envelope is with list

(a and [p(1)] or [p(2)])[0]

Given not-empty list as x, bool(x) is True.

How can I make a function?

"def" statement to make functions also requires "new line". So you must use "lamnda".

But lambda function can include expressions, not statements. You can't use assignments in lambda functions.

Oops, I can't use assignments?!

Don't worry. Python's great introspection allow you to remove assignment statements. The builtin function "globals()" returns global namespace as a dictionary. So when you want to do "x = 1", you just do "globals().__setitem__('x', 1)". Very easy. Sometimes you may use "locals()" for a local namespace and "x.__dict__" for a member of object x, but good programmers don't need them, because they use global namespace only.

How can I use "for" statements?

Why don't you use the list comprehension? I thought "for" statements were obsoleted.

>>> for i in range(5):
	print i

	
0
1
2
3
4
>>> import sys;[sys.stdout.write(str(i) + "\n") for i in range(5)]
0
1
2
3
4
[None, None, None, None, None]

[None, None, None, None, None] is the value of this expression. It is as True. You may have to use "and 0" to make it as False.

Is "while" statement replaced with recursive call?

Partially, yes. But if it loops too many times, it causes "RuntimeError: maximum recursion depth exceeded".

The other solution is lazy evaluation and infinite list. Import "ifilter" and "count" from itertools. "count" is a infinite list. "ifilter" creates a filtered list lazily. So "ifilter(bool, x).next()" evaluates x[0], x[1], x[2], ..., and stop iteration if x[n] is True.

>>> i = 1
>>> while i < 100:
	i *= 2

	
>>> i
128
>>> from itertools import ifilter, count; i = 1; ifilter(bool, ((i >= 100) or gl
obals().__setitem__("i", i * 2) for x in count())).next()
True
>>> i
128

How to substitute "break" statement and "else" clause?

It is very difficult. It is NOT difficult to write in Python, BUT difficult to write in English! "if condition: break" means "When the value of expression become paticular value, stop iteration". It is similar to the end of "while" statement. That is, the expression in "ifilter" should be as True when either the loop ended and the loop breaked. "else-clause" distinguish those two tarmination, so the value of expression must be different value.

I'll make this code to calculate prime numbers to oneliner.

>>> primes = []
>>> for i in range(2, 100):
	for p in primes:
		if i % p == 0:
			break
	else:
		primes.append(i)

>>> primes
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]

First, substitute the "for" statement by a "while" statement.

>>> primes = []
>>> for i in range(2, 100):
	j = 0
	while j < len(primes):
		if i % primes[j] == 0:
			break
		j += 1
	else:
		primes.append(i)

		
>>> primes
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]

I make the expression when "i % primes[j] == 0" the value becomes "BREAKED". When the loop tarminated without breaked, the value of loop become "True". After loop tarminated, if the value is "True", do "else-clause".

>>> globals().__setitem__("primes", []) or [
  globals().__setitem__("j", 0) or
  ifilter(bool,
    (
      not(j < len(primes)) or
      (i % primes[j] == 0 and "BREAKED") or
      globals().__setitem__("j", j + 1)
      for c in count()
    )
  ).next() == True and primes.append(i)
  for i in range(2, 100)
] and None
>>> primes
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]

And I removed newlines and redundant spaces.

>>> globals().__setitem__("primes",[])or[globals().__setitem__("j", 0)or ifilter
(bool,(not(j<len(primes))or(i%primes[j]==0 and"BREAKED")or globals().__setite
m__("j",j+1)for c in count())).next()==True and primes.append(i)for i in range(2
,100)]and primes
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]

How can I define a class?

There is no need to define your own class.

First, find a nice not read-only class or import it. Make an instance of the class. And push all fields and methods you need into it! Push, push, push!

If you need multiple instance, envelope the pushing code with lambda and make "builder function".

Here I wrote a sample to define a class.

>>> class Counter:
	def __init__(self):
		self.count = 0
	def __call__(self):
		self.count += 1
		return self.count

	
>>> c = Counter()
>>> c()
1
>>> c()
2

Import HTMLParser from HTMLParser, and push and push and push.

>>> from HTMLParser import HTMLParser; self = HTMLParser(); self.count = 0; self
.__call__ = lambda :self.__dict__.__setitem__("count", self.__dict__["count"] + 
1) or self.count
>>> self()
1
>>> self()
2

If you envelope them with lambda and assign it in global namespace, you can emulate the class definition.

>>> globals().__setitem__("Counter", lambda :(lambda self: self.__dict__.__setit
em__("count", 0) or self.__dict__.__setitem__("__call__", lambda :self.__dict__.
__setitem__("count", self.__dict__["count"] + 1) or self.count) or self)(__impor
t__("HTMLParser").HTMLParser()))
>>> c = Counter()
>>> c()
1
>>> c()
2
>>> c2 = Counter()
>>> c2()
1
>>> c()
3

How to "try" without "try...except"?

To catch a exception without try-statement is almost impossible. But I had to catch "Software caused connection abort" in my oneliner. I found a solution, it is not perfect substitution of "try...except", but it works.

Run the dengerous code as subprocess. When the subprocess dead, read its error message from the pipe and parse it.

    if sys.argv[3] == "CATCH":

        ifilterfalse(bool,
            (
                re.search("Software caused connection abort",
                    os.popen3(
                        r"python %s %s %s GO" % (
                            sys.argv[0],
                            sys.argv[1],
                            sys.argv[2]
                        )
                    )[2].read()
                )
                for x in count()
            )
        ).next()


    elif sys.argv[3] == "TRY":
        # dengerous code

It is work like following code.

while True:
    try:
        #  dengerous code
    except ....: # catch "Software caused connection abort" and ignore it
        pass

If you need some values from subprocess, you can use "cPickle" library. "cPickle.dumps(...)" and "globals.update(cPickle.loads(...))".

How to make import statements to expression?

Is it nessesary? If it is really nessesary, use built-in function __import__. But if you use global namespace only, you can simply import on the head of your code.

How to make short oneliner?

Find repeated string and make shorter. For example, "globals().__setitem__" is very frequent. Do "globals().__setitem__("g",globals().__setitem__)" or "globals().__setitem__("g",lambda x,y,z=globals():z.__setitem__(x,y))". If you have "not read-only and not callable" object x, try "x.__dict__.__setitem__("__call__", x.__dict__.__setitem__)".

Or compress it.

# Brainf*ck interpreter in Python Onliner Compressed
exec(reduce(lambda x,y:x.replace(y[0],y[1:]),'O1)q|Pz"t",|Qz"c",|Rimport |SY:zp,
|T)%256X|UY:z"c",c+1qp",p|V)or ifilter(bool,(|W)for x in count())).next()|Xqc",c
+1)q|Y",lambda|Z(globals().get(p,0)|q)or z"|zglobals().__setitem__('.split('|'),
'Rsys;from itertools Rcount,ifilter;[Q0qp",0qjY k:lambda:Z==0)^(k==-1)and(Pc+kqd
",1Vz"d",d+{"]":-1,"[":1}.get(s[t],0)*k)or d==0 or Pt+kWand Qt+1)or 1X>U+O<U-O+S
Z+1T-SZ+255T.Y:sys.stdout.write(chrZ)X,Sord(raw_input(">")[0]T[",j(O]",j(-Os",fi
le(sys.argv[1]).read()Vc==len(s)or(globals()[s[c]]()and 0W]'))

afterword

Thank you for reading this awful code written in English. I appreciate your patch to debug my English. Please feel easy to contact me!

KEMURI

This entry is an introduction of new programming language. Here is Japanese version.

KEMURI (means 'smoke' in Japanese) is proposed by NISHIO Hirokazu and OBINATA Daichi in the 39th symposium for young researcher of information science (jouhou kagaku wakate-no-kai in Japanese).

This is a code to print "Just Another Python Hacker," in KEMURI. Notice it is not the shortest code to print that. "^^"^^ can be replaced by ^"^^.

`"^^"^^^^"^^'"^^"^^'"^^"^^'"^^"^^"'"^^"^^`"^^"^^^^"^^"^^"^^"^^"^^'"^^"^^"'"^^"^^
`"^^'^^'"^^"^^'"^^"^^'"^^"^^'"^^"^^"'"^^"^^`'"^^"^^^^'"^^^'"^^"^^'"^^"^^'"^^"^^`
"^^"^^^^^^'"^^"^^'"^^"^^'"^^"^^`"^^"^^"^^'"^^^'"^^"^^'"^^"^^'"^^"^^^`'"^^"^^'"^^
"^^'"^^"^^'"^^"^^'"^^"^^'"^^"^^`"^^"^^^^"^^"^^'"^^"^^'"^^"^^'"^^"^^`"^^"^^^^'"^^
^'"^^"^^'"^^"^^'"^^^`"^^"^^^^'"^^"^^'"^^"^^'"^^"^^'"^^"^^`'"^^''^^'"^^"^^^'"^^"^
^'"^^"^^'"^^"^^`"^^"^^^^"^^"^^"^^^'"^^^'"^^"^^`"^^"^^^^"^^"^^"^^"^^''"^^^^'"^^"'
`'"^^"^^'"^^"^^'"^^"^^^^'"^^"^^'"^^"^^"'`"^^"^^^^"^^"^^'"^^"^^'"^^"^^'"^^"^^'"^^
"^^`"^^"^^^^"^^"^^"^^"^^"^^'"^^"^^"'"^^"^^`"^^'^^'"^^"^^'"^^"^^'"^^"^^'"^^"^^"'"
^^"^^`'"^^''^^'"^^"^^^'"^^"^^'"^^"^^'"^^"^^`"^^"^^^^"^^"^^"^^^'"^^^'"^^"^^`"^^"^
^^^'"^^"^^'"^^"^^'"^^"^^'"^^"^^`"^^"^^^^'"^^^'"^^"^^'"^^"^^'"^^^`^^'"^^"^^'"^^"^
^'"^^"^^'"^^"^^'"^^"^^`"^^"^^^^"^^"^^'"^^"^^'"^^"^^'"^^"^^`"^^"^^^^"^^"^^"^^^'"^
^^'"^^"^^`"^^"^^^^"^^"^^'"^^"^^^'"^^"^^^`'"^^"^^'"^^"^^'"^^^'"^^^^'"^^''`"^^"^^^
^"^^"^^^^^'"^^"^^'"^^"^^"'^"^^|

KEMURI is a Stack machine. You can push byte values (from 0 to 255) into stack. Each letter in KEMURI code is a command. There are only 6 commands in KEMURI syntax. The ^ pops two value from the stack and calculates XOR and pushes the result. The " duplicate the top value of the stack, that is, it pops a value and pushes itself twice. The ' pops three values x, y, z and pushes x, z, y. In other word, it rotates the top three values of the stack from xyz to yzx. The ~ pops a value and calculate NOT and pushes the result. The only command to push constant values into the stack is the `. It pushes 13 values 33, 100, 108, 114, 111, 119, 32, 44, 111, 108, 108, 101, 72 in this order. The | prints all values in the stack to standard output. It is strongly recommended to use it only once at the tail of your code.

To print "Hello, world!", you just type two keys as below. It is the shortest code to print "Hello, world!" all over the world, except for HQ9+.

`|

KEMURI has many advantages. It can print any character, which HQ9+ can't. It has only 6 commands so it is easier to learn Brainf*ck.

"l"(small L) and "*"(asterisk) are reserved for possibility to use as a command "Execute the stack as Brainf*ck" in future.

I wrote a KEMURI interpreter in Python.

続きを読む "KEMURI" »

2006年03月31日

DownloadableYouTube

This is a bookmarklet to make all link from YouTube search result downloadable.

How to use

Bookmark this link. (Right-click the link and add to bookmark.) And then click the bookmark on a search result of YouTube. So all links change not to a browse page but to a download cgi. You can save the movie with right-clicking them and choose "save as..".

How to see the downloaded files

The format of those movies is *.FLV (Flash Movie), so you need a flv player. If you don't have it, get "Free Riva FLV Player 1.2" from Riva VX: Downloads.

How it works

An URL like "http://www.youtube.com/watch?v=********" is a page to browse movie. The bookmarklet replace all url like above to like "http://youtube.com/get_video.php?video_id=********". It is a cgi to get movie.

I made this on a Firefox, and I didn't check its behavior on IE.

2006年03月23日

TagTrace ver0.2(English)

"TagTrace" is a bookmarklet to make easy to customize CSS.

Feature

  • Highlight mouse-overed tag to show its bounds.
  • Show the name, class and ID of mouse-overed tag in tooltip text.
  • Show tag hierarchy from clicked tag to HTML tag in the bottom of the page.

How to use

Download following script, upload it and make bookmark to

javascript:(function(){var s=document.createElement("script");s.charset="UTF-8";s.src="http://www.nishiohirokazu.org/testJS/tagTrace.js";document.body.appendChild(s)})();

Here "http://www.nishiohirokazu.org/testJS/tagTrace.js" is the position which you upload the script.

Or simply bookmark this.

The latter method use the script on my server, so it will change its behavior or stop its activity.

Known problem

  • When you clicked button, link etc. its ORIGINAL function works before the tag trace. The original function must be disabled with some techniques.

Source code

Download
colorArray=new Array();
borderArray=new Array();
currentTag = undefined;
tagTrace = undefined;

tags = document.getElementsByTagName('*');
for(i = 0; i < tags.length; i++){
	tag = tags[i];
	t = tag.tagName;
	if(tag.className != ""){
		t += "." + tag.className;
	}
	if(tag.id != ""){
		t += "#" + tag.id;
	}
	tag.title = t;
	
	tag.onmouseover=function(){
		if(currentTag){
			return;
		}
		currentTag = this;
		t=this;
		colorArray[t]=t.style.background;
		borderArray[t]=t.style.border;
		t.style.background='#DAFADA';
		t.style.border='solid';
	};
	tag.onmouseout = function(){
		t=this;
		t.style.background=colorArray[t];
		t.style.border=borderArray[t];
		currentTag = undefined;
	};
	tag.onclick = function(){
		t = this;
		if(!tagTrace){
			tagTrace = ""
		}
		tagTrace += t.title + "\n";

		var tmp = document.createElement("div");
		tmp.innerHTML = t.title + "\n";
		document.body.appendChild(tmp);

		if(!t.parentNode){
			alert(tagTrace);
			tagTrace = undefined;
		}
	};
}

2006年03月13日

English test

Sometime I want to write entries in English because some information is usefull in all over the world. Maybe my English is not so good but it is not much problem.

古い記事タイトル一覧

凡例{ ●: 単一エントリーへのリンク, □: そこから最新記事までを一覧表示, ■: そこから最新記事までをwindow.openで開く}(comming soon)