コマンドライン引数のワイルドカードを展開する

今日も Python ネタ。

とかいいつつ Ruby の話から入るけど、Ruby はコマンドラインのワイルドカードを展開してくれる。

^o^ > type argv.rb
ARGV.each {|a| puts a}

^o^ > ruby argv.rb *.py
argv.py
binary_search.py
bubble_sort.py
counting_sort.py
count_char.py
count_files.py
csv_read.py
csv_write.py
default_arg.py
dict.py
dictionary.py
dict_keys.py
difference.py
difference2.py
enumerate.py
exception1.py
exception2.py
exception3.py
expand_num.py
(以下略)

でも、Python はそんな気の利いたことしてくれない。

^o^ > type argv.py
import sys

print sys.argv


^o^ > python argv.py *.py
['argv.py', '*.py']

そこで、glob モジュールの出番になる。

 cf. 10.7. glob — Unix 形式のパス名のパターン展開

import sys
import glob

files = glob.glob(sys.argv[1])
for file in files:
    print file

実行:

^o^ > python argv2.py *.py
argv.py
argv2.py
binary_search.py
bubble_sort.py
counting_sort.py
count_char.py
count_files.py
csv_read.py
csv_write.py
default_arg.py
dict.py
dictionary.py
dict_keys.py
difference.py
difference2.py
enumerate.py
exception1.py
exception2.py
exception3.py
expand_num.py
(以下略)

辞書を値でソートする

Python で辞書をソートしようとすると、

>>> h = {'a' : 200, 'b' : 300, 'c' : 500, 'd' : 100, 'e' : 400}
>>> for k, v in sorted(h):
...    print k, v
...
Traceback (most recent call last):
  File "", line 1, in 
ValueError: need more than 1 value to unpack

エラーになった。これは、sorted(h) がキーしか返さないからだ。

>>> for k in sorted(h):
...     print k
...
a
b
c
d
e

キーと値がほしいときにはこうする。

>>> for k, v in sorted(h.items()):
...     print k, v
...
a 200
b 300
c 500
d 100
e 400

辞書の items メソッドは、キーと値からなるタプルのリストを返してくれる。

>>> h.items()
[('a', 200), ('c', 500), ('b', 300), ('e', 400), ('d', 100)]

で、そのタプルの第1要素でソートされる。つまり辞書のキーでソートされるわけだ。

でも、今日やりたいのは値でソートすること。そのためには、sorted に key 引数を渡してやればいい。具体的にはこうする。

>>> for k, v in sorted(h.items(), key=lambda x: x[1]):
...     print k, v
...
d 100
a 200
b 300
e 400
c 500

key 引数に渡しているのは、タプルの第2要素を返す関数だ。つまりこの関数の返り値でソートされるわけだな。
ちなみに、降順にするには、reverse=True を渡してやる。

>>> for k, v in sorted(h.items(), key=lambda x: x[1], reverse=True):
...     print k, v
...
c 500
e 400
b 300
a 200
d 100

__main__.py

今日は Python。

ディレクトリやzipファイルに、__main__.py という名前のスクリプトを含めておくと、そのディレクトリやzipファイルを Python の引数に指定することで、__main__.py が実行される。

例を示そう。

print "Hello, Python."

これを、hello フォルダの中においておく。で、次のように実行すると:

^o^ > ls hello
__main__.py

^o^ > python hello
Hello, Python.

このとおり、__main__.py が実行された。

zipファイルにした場合も同じように動く。

^o^ > cd hello

^o^ > zip hello.zip __main__.py
  adding: __main__.py (164 bytes security) (stored 0%)

^o^ > python hello.zip
Hello, Python.

こんな機能があったとは。でも、どういうときに使うんだろ。

トリボナッチ数をSchemeで

昨日は Python でやったので、今日は Scheme で。

(define tribonacci
  (lambda (n)
    (let loop ((m n) (l '(0 0 1)))
      (if (= m 0)
          '()
          (cons (car l) (loop (- m 1) (append (cdr l) (list (apply + l)))))))))

(print (tribonacci 20))

今回は名前つきletで再帰。
実行:

^o^ > gosh tribonacci.scm
(0 0 1 1 2 4 7 13 24 44 81 149 274 504 927 1705 3136 5768 10609 19513)

トリボナッチ数

トリボナッチ数というのを知った。

 cf. フィボナッチ数,トリボナッチ数 – arik_egaのノート

要するに、フィボナッチ数が前2項の和であるのにたいして、トリボナッチ数は前3項の和である数。最初の3項は 0,0,1。詳しくは Wikipedia で。

Python のジェネレータで書いてみた。

def tribonacci(n):
    a, b, c = 0, 0, 1
    m = 0
    while m < n:
        yield a
        a, b, c = b, c, (a + b + c)
        m += 1

for t in tribonacci(20):
    print t [/crayon]

この例では、最初の20項を出力している。 実行例:

^o^ > python tribonacci.py
0
0
1
1
2
4
7
13
24
44
81
149
274
504
927
1705
3136
5768
10609
19513

eq?とeqv?とequal?

違いがよくわからなかったのでメモ。

6.2 等価 – Gauche ユーザリファレンス によると次のような違いがある。

eq?

最も高速で、細かい区別ができる述語。 2つの引数がアロケートされる同じ型のオブジェクトで、かつ両者がメモリ上の全く同じ場所を占めるオブジェクトを指している場合に #t を返す。2つの引数がともに文字、あるいは数値だった場合の振るまいは Scheme の標準では定められていない。

gosh> (eq? 'Foo 'Foo)
#t
gosh> (eq? "Foo" "Foo")
#f
gosh> (eq? #\a #\a)
#t
gosh> (eq? 123 123)
#t
gosh> (eq? '(Foo) '(Foo))
#f

Gauche の場合には文字列では #f になるけど、数値では #t になるな。

eqv?

2つの引数 obj1 と obj2 がともに正確な数値、あるいはともに(NaN以外の)不正確な数値である場合、(= obj1 obj2)が真であれば #t が、偽であれば #f が返される。obj1 と obj2 がともに文字である場合、(char=? obj1 obj2)が真であれば #t が、偽であれば #f が返される。それ以外の場合は、Gaucheでは eqv? は eq? と同じ。

gosh> (eqv? 'Foo 'Foo)
#t
gosh> (eqv? "Foo" "Foo")
#f
gosh> (eqv? #\a #\a)
#t
gosh> (eqv? 123 123)
#t
gosh> (eqv? '(Foo) '(Foo))
#f
gosh>

eq? と同じじゃん。正確な数値とか不正確な数値とかがわかんないけど。

equal?

2つに引数 obj1 と obj2 がリストやベクタなどの複合型である場合、equal? は再帰的に対応する要素同士を equal? で比較する。そうでなければ equal? は eqv? と同じようにふるう。

gosh> (equal? 'Foo 'Foo)
#t
gosh> (equal? "Foo" "Foo")
#t
gosh> (equal? #\a #\a)
#t
gosh> (equal? 123 123)
#t
gosh> (equal? '(Foo) '(Foo))
#t

eq? や eqv? では #f になった文字列やリストでも #t になる。

まとめ

表にまとめると次のようになる。

オブジェクト eq? eqv? equal?
シンボル #t #t #t
文字列 #f #f #t
文字 #t #t #t
数値 #t #t #t
リスト #f #f #t

比べるのがシンボルの場合には eq?、文字の場合には eqv?、数値の場合には(上には出てこないけど)=、それ以外は equal? がいいみたいだ。

シンボル型

シンボル型とは、「一言で言うとシンボルとは、文字列をアドレスで管理するデータ型」らしい。

 cf. 12. シンボル型 – もうひとつの Scheme 入門

Ruby のシンボルと同じようなものだと考えてよさそうだ。
シンボルを比較するには、アドレスを比較する eq? が使えるので、高速に比較することができる。なので、連想配列やハッシュ表のキーに使うといいようだ。

今までのエントリに出てきた中では、数値以外のアトムが実はシンボルだった。シンボルを使うにはクォートしてやらないといけない。そうでないと Scheme は変数として評価しようとする。

gosh> foo
*** ERROR: unbound variable: foo
Stack Trace:
_______________________________________
gosh> 'foo
foo

文字列とは違うことに注意。

gosh> (symbol? 'foo)
#t
gosh> (symbol? "foo")
#f

シンボルと文字列は相互に変換できる。文字列からシンボルへは string->symbol、シンボルから文字列へは symbol->string だ。

gosh> (string->symbol "Foo")
Foo
gosh> (symbol->string 'Foo)
"Foo"

処理系にもよるけど、文字列をシンボルに変換するとき小文字にしておかないと、同じつづりでも同じアドレスにならないらしい。

gosh> (eq? (string->symbol "Foo") 'Foo)
#t

同じアドレスでないと、これが #f になるわけだな。Gauche の場合は同じになるようだ。

Pythonで文字列を固定長でスライスする

たまには Python も書かねば。

タイトルのとおりなんだけど、ちょうどいい関数やメソッドが見当たらなかったので書いた。
要するに Ruby の Enumerable#each_slice みたいなのの文字列版。

def string_each_slice(s, n):
    i = 0
    r = []
    while i < len(s):
       r.append(s[i:i+n])
       i += n
    return r

s = "abcdefg"
print string_each_slice(s, 2)
^o^ > python string_each_slice.py
['ab', 'cd', 'ef', 'g']

最後が指定した固定長に足らない場合は、足らないまま返す。まあ、これは Ruby の Enumerable#each_slice と同じ振る舞いにしただけ。

文字と文字列

今日は文字と文字列について。
参考ページ:

 cf. 11. 文字、文字列 – もうひとつの Scheme 入門
 cf. 6.10 文字 – Gauche ユーザリファレンス
 cf. 6.12 文字列 – Gauche ユーザリファレンス

文字

文字のリテラルは #\ に続けて文字を書く。たとえば a という文字を表すには #\a とする。なんか変な感じ。

gosh> #\a
#\a

あと、いくつかの特殊文字などには名前がついている。名前は大文字と小文字を区別しない。

  • #\space
  • #\newline
  • #\return
  • #\tab
  • #\delete
  • #\null

以下、文字にかんする関数をいくつか。

(char? obj) は obj が文字なら真を返す。

gosh> (char? #\a)
#t

(char=? c1 c2) は文字が等しければ真を返す。

gosh> (char=? #\a #\a)
#t

(char->integer c) は文字を整数(ASCIIコード)に変換する。(integer->char n) はその逆。

gosh> (char->integer #\a)
97
gosh> (integer->char 97)
#\a

(char-alphabetic? c)(char-numeric? c)(char-whitespace? c)(char-upper-case? c)(char-lower-case? c) はそれぞれ、c がアルファベット、数字、空白文字、大文字、小文字のときに真を返す。

gosh> (char-alphabetic? #\a)
#t
gosh> (char-numeric? #\1)
#t
gosh> (char-whitespace? #\space)
#t
gosh> (char-upper-case? #\A)
#t
gosh> (char-lower-case? #\a)
#t

(char-upcase c)(char-downcase c) はそれぞれ、大文字、小文字に変換する。

gosh> (char-upcase #\a)
#\A
gosh> (char-downcase #\A)
#\a

文字列

文字列のリテラルは、たとえば “abc” みたいに ” でくくる。こっちは普通な感じ。

(string? s) は s が文字列なら真を返す。

gosh> (string? "foo")
#t

(string-length s) は文字列の長さ。

gosh> (string-length "foo")
3

(string=? s1 s2) は s1 と s2 が等しいとき真を返す。

gosh> (string=? "foo" "foo")
#t

(string-ref s idx) は s の idx番目の文字を返す。idx は0から。

gosh> (string-ref "abcde" 3)
#\d

(substring s start end) は start番目 から end – 1 番目の部分文字列を返す。Python のスライスと同じ要領だな。

gosh> (substring "abcde" 2 4)
"cd"

(string-append s1 s2) は文字列の連結。

gosh> (string-append "foo" "bar")
"foobar"

(string->list s)(list->string ls) は文字列とリストの変換。

gosh> (string->list "abc")
(#\a #\b #\c)
gosh> (list->string '(#\a #\b #\c))
"abc"

こんなところか。もっと詳しくは参考ページで。

練習問題

最後に練習問題をやっておこう。11. 文字、文字列 – もうひとつの Scheme 入門 より。

単語の初めを大文字にする関数 title-style を書いてください。

(define title-style
  (lambda (str)
    (letrec ((u (lambda (l acc)
      (cond
        ((null? l) (list->string (reverse acc)))
        ((char-whitespace? (car l)) (u (cdr l) (cons (car l) acc)))
        (else (d (cdr l) (cons (char-upcase (car l)) acc))))))
          (d (lambda (l acc)
            (cond
              ((null? l) (list->string (reverse acc)))
              ((char-whitespace? (car l)) (u (cdr l) (cons (car l) acc)))
              (else (d (cdr l) (cons (car l) acc)))))))
                (u (string->list str) '()))))

(print (title-style "one size fits all"))

実行結果:

^o^ > gosh title-style.scm
One Size Fits All