Python で wave ファイル生成

wave 形式の音声ファイルを出力する Python プログラム。

#!/usr/bin/env python
import wave, math, array
SAMPFREQ = 44100
LENGTH = 3

def wave_init(fname, sampf):
   f = wave.open(fname, 'w')
   f.setnchannels(1)
   f.setsampwidth(2)
   f.setframerate(sampf)
   f.setcomptype('NONE', 'not compressed')
   return f
 
def prepare_array(n):
   data = array.array('h')
   data.extend([0]*n)
   return data
 
def wave_write(f, data):
   f.writeframesraw(data.tostring())
   f.close()
 
def sin_wave(fname, freq):
   f = wave_init(fname, SAMPFREQ)
   data = prepare_array(SAMPFREQ * LENGTH)
   a = math.pi * 2.0 * float(freq) / float(SAMPFREQ)
   for i in range(SAMPFREQ * LENGTH):
      ft  = int(math.sin(a * float(i)) * 30000.0)
      data[i] = ft
   wave_write(f, data)
 
if __name__ == "__main__":
   sin_wave('sinwave.wav', 440)

実行すると,カレントディレクトリに sinwave.wav というファイルが出来上がります。
おもしろい。

参考文献:
千葉大学 情報通信システム 講義資料(PowerPoint)

そして,この資料で面白いと思ったのはこっちです。この授業受けてみたいなぁ。


Google App Engine で JSON 出力

海外のブログを見ていたら,こんな記述をみつけました。

GAE doesn’t include ‘simplejson‘ in the Python container so you are going to have to include it with your application. I downloaded simplejson-1.8.1 and symbolically linked its simplejson directory into my application directory.

そんなことないですよね。 simplejson パッケージが django.utils に含まれているので,次のようにすれば JSON 形式で出力することができます。日本語文字列を含む場合は, ensure_ascii=False とするところがポイント。

# -*- coding: utf-8 -*-
import wsgiref.handlers
from django.utils import simplejson
from google.appengine.ext import webapp

class hoge(webapp.RequestHandler):
    data = {"cancam_models": [{"name": u"蛯原友里", "age": 28},
                              {"name": u"徳澤直子", "age": 23},
                              {"name": u"西山茉希", "age": 22},]}
    self.response.content_type = “application/json”
    simplejson.dump(data, self.response.out, ensure_ascii=False)

また,最後の行を次のようにすると,JSONP 形式で出力できます。

self.response.out.write("%s(%s)" %
    (callback, simplejson.dumps(data, ensure_ascii=False)))


関連リンク:
simplejson - Google Code

3の倍数と3のつく数字(世界のナベアツ)

» 力試しにナベアツのような判定をするプログラムを作ろうとしたところ…

Pythonだとこんな感じで1行で書けるんだけど,これじゃだめなのかなぁ

(num % 3 == 0) or ('3' in `num`)
実行例:
>>> num = 12345
>>> (num % 3 == 0) or ('3' in `num`)
True

>>> num = 14
>>> (num % 3 == 0) or ('3' in `num`)
False

追記:
文字列として扱ってはいけない理由が分からないけど,あくまでも数値として扱うとこんな感じかな。やっぱりPythonはすっきりと書けて,他の人が読んだときに理解しやすい気がする。

def include3(num):
    if num % 10 == 3:
        return True
    if num > 10:
        return include3(num / 10)
    return False
実行例:
>>> num = 12345
>>> (num % 3 == 0) or include3(num)
True

>>> num = 14
>>> (num % 3 == 0) or include3(num)
False

追記:
後で調べたら,はてダでこの問題を解いてる人がけっこういたのですが,下の2つには強烈なセンスを感じました。世の中には面白い人がいるもんだなぁ。

» ナベアツ問題これは難しい・・・ - miura1729の日記
 BCD表現で解いてるw
» GPUで「世界のナベアツ」問題 - 桃の天然水
 GPUのシェーダ機能を使ってる

Google App Engine で XML をパースする方法

誤解があるといけないので書きますが,「Google App EngineにXMLパーサが入っていない」ということはありません。 ElementTree という Python 標準モジュールがふつうに使えるので,特に App Engine だからといって意識する必要はありません。Pythonで書かれたpure Python版とCのライブラリを利用したものがありますが,どちらでもOKです。好きな方をインポートしてください。

pure Python版
from xml.etree import ElementTree
Cライブラリ版
from xml.etree import cElementTree

例えば,Twitter の XML を取得してきて,パースして名前と本文を表示するのは,こんな感じでできます。簡単ですね。

import xml.etree.cElementTree as etree
from google.appengine.api import urlfetch

url = 'http://twitter.com/statuses/public_timeline.xml'
xml = urlfetch.fetch(url).content
dom = etree.fromstring(xml)

for st in dom.findall('./status'):
    name = st.findtext('user/screen_name').encode('utf-8')
    msg = st.findtext('text').encode('utf-8')
    print "%s: %s\n" % (name, msg)

簡単に説明すると, status エレメントでループして,その中から screen_name と text エレメントのテキストを取り出して表示しています。ちなみに,Twitter public timeline の XML はこんな感じです。

<?xml version="1.0" encoding="UTF-8"?>
<statuses type="array">
  <status>
    <created_at>Fri Apr 11 14:36:25 +0000 2008</created_at>
    <id>787211133</id>
    <text>ニコニコ ドウガ ヲ ミテイマース</text>
    <source><a href="http://twitterfeed.com">twitterfeed</a></source>

    <truncated>false</truncated>
    <in_reply_to></in_reply_to>
    <in_reply_to_user_id></in_reply_to_user_id>
    <user>
      <id>7999382</id>
      <name>fileunder</name>
      <screen_name>fileunder</screen_name>

      <location>Amersfoort</location>
      <description>Regelneef van FileUnder. Al lijkt het soms ook wel eens een vorm van ehm ehm nu ja zoiets.</description>
      <profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/28244052/DSC00034_normal.jpg</profile_image_url>
      <url>http://www.fileunder.nl</url>
      <protected>false</protected>
      <followers_count>76</followers_count>

    </user>
  </status>
  <status>
  …
  </status>
</statuses>

# 本当は, lxml を使えると最高なんですけどね…

Google App Engine について知っておきたいこと

まだベータリリースではありますが,4月8日に Google App Engine が公開されました。ひと言でいうと,Webアプリケーションを簡単に公開することができる開発/ホスティング環境です。
特徴としては,

  • アプリケーションごとに500MBのストレージ,月に5,000,000ページビューまで利用可能
  • 無料(正式リリース後は有料オプションで上記の上限超過にも対応)
  • 現時点で開発言語は Python のみ対応(Djangoベース)
  • SDKをダウンロードすることでローカルで開発可能,デプロイも簡単
  • 管理用ダッシュボードが用意されていてCPU使用率,ログなどを閲覧可能

で,Google App Engineは何がいいのか?ということなのですが,僕は次のように考えています。

まず,個人や小さなベンチャー企業がWeb上でサービスを公開しようとした時に必要な初期投資がほぼ要らなくなります。現在は,さくらなどでレンタルサーバを借りてサーバをセットアップして…といった作業をしているかと思いますが,これが必要なくなります。

次に,サービス初期の段階ではサーバ1台で始めて,アクセス数が多くなってきたら負荷分散を考えるといった「小さく始めて大きく育てる」ということが,Googleの誇るインフラを使って非常に簡単にできます。通常はアクセス数が増えると,それに対応できるようにシステムに大幅な改修が必要になります。それが,Googleが培ってきた技術を用いることで,アプリケーション開発者が全く意識することなく,スケールと負荷分散を自動的に行ってくれます。数百人しか利用していないサービスが突如人気が出て,数万人規模になっても何もしなくてもGoogle App Engineのインフラがよきに計らってくれます。

ここの部分は非常に重要で,大手の会社でもこの作業に失敗して何日もサービスを止めるなんてことがざらにあります(昨年もありましたね…)。Webアプリケーションを開発できるエンジニアというのは世の中にたくさんいますが,スケール可能な設計にしたり,それを実際に構築したりすることができるエンジニアっていうのは割と少なくて,僕が前に在籍していたウノウでも,CTOの尾藤さんや最近退職したid:dandasoくらいだったと思います(俺もできるよって人がいたらごめんなさい)。しかしこれからは,サーバの知識がなくても「優れたアイデア」と「少しのプログラム開発力」さえあれば,魅力的なサービスの運営ができてしまうということになります。

次に開発環境の話になりますが,現時点で対応している言語は Python のみです。開発用のフレームワークとしては,標準で Django が利用可能です(実はこのブログもDjangoで動いています)。ただし,Google のインフラを利用するために Model まわりに大きく手が入っていて,既存の Django アプリケーションをそのまま移行することはできません。データの取得方法も慣れ親しんだO/Rマッパー方式ではなく,ほぼ SQL と同一ではありますが独自の GQL という形式で記述が必要です。この辺りは,少しだけネックになるかもしれません。一度,Google App Engine用に作ってしまうと,他の環境に移すことが難しくなります。また,開発効率の高さから一部では盛り上がっている Django ですが,まだまだ開発者がそんなに多いわけではないのも少し問題です。しかし,これは逆にエンジニアにとっては新たなチャンスになるかもしれません。Django は比較的習得が容易ですし,ちょっとやる気を出すだけで Google のインフラを使って差別化ができるわけですから。

最後に,あまりよく知られていないであろう部分をまとめておきます。


■ Django以外のPythonフレームワークも使える

標準でサポートしているのは,Djangoベースのものになりますが,他のPython製フレームワークが使えないわけではありません。WSGIに準拠したCherryPy, Pylons, web.pyなどが利用可能です。
利用可能なんですが… 後述するようにネイティブCの一部ライブラリが使えないために例えば Pylons を簡単に動かせるかというとちょっと難しいようです。 

■ 独自ドメインも使える

登録したアプリケーションは,***.appspot.comという名前がデフォルトですが,Google Appsの設定をすることで独自ドメインも使えます。詳細はこちら。

» http://code.google.com/appengine/articles/domains.html

■ 1アカウントで3アプリケーションまで登録可能,ただし削除できない

開発用のアカウントを登録すると,***.appspot.comといったアプリケーションを3つまで登録可能です。でも,今のところ削除することができません。もし,ミスタイプして変なidを取ってしまったら最悪です。注意しましょう。

■ socketやftplibなどのライブラリは使えない

「Google App Engine Python Library Support」に記載されている一部のネイティブCのライブラリが利用可能です。他にピュアPythonで記述されたライブラリはだいたい使えるようです。ただし,子プロセスやスレッド機能は使えません。また,imp, ftplib, select, socket, tempfileなどのモジュールも使えません。HTTP/HTTPS以外で通信したり,動画変換などを行うサービスはできないと考えたほうがよいです。

■ 何から始めたらいいか

まずはチュートリアルを順番にやってみることをお勧めします。Web開発をしたことがある人であれば,Pythonの知識がなくても分かりやすいと思います。次に Datastore APIUsers API に目を通してみましょう。そして,一通り使えるようになったら,Samples for Google App Engineを見ると,さらに発見があるかもしれません。


以上で,自分なりにまとめてみた Google App Engine の概要は終わりです。近々,ウノウに会場をお借りして,Google App Engine 勉強会を開催できたらいいなぁなどと考えています。興味のある人がどれだけいるのかは分かりませんが,詳細が決まりましたらまた追ってお知らせしたいと思います。

Google App Engine リリース間近,最初は Python のみサポート

Googleが月曜日に何か大きな発表をする,と噂されていたものの正体は「Google App Engine」というサービスのようです。TechCrunchに記事が上がるやいなや,かなりの盛り上がりを見せています。Googleが誇るBigTableとGFSが利用可能なアプリケーション用の実行環境で,Amazon EC2に対抗するようなもののようです。ベータリリース時には10,000人限定で公開するようですが,サポートされる言語はPythonのみ。今後,他の言語もサポートしていくようですが,Python開発者のGuido van RossumがいるGoogleは,Pythonにフォーカスしていくということでしょうね。非常に楽しみです。

» Google App Engine

※まだ上のリンクを辿っても何もありませんが,日本時間の13時頃に例のキャンプファイヤーで公開される模様です。

関連リンク:
» Live From Google Campfire One - TechCrunch
» App Engine: Host Your Apps with Google - O'Reilly Radar


追記:Guidoの動画が公開されました。Django 0.96.1が最初から使えるようです ↓

シカクいアタマをマルくする問題 その1

清水川さんのブログに書いてあったこの問題をPythonで解いてみました。

回文数

"121" や "3333" のように右から読んでも左から読んでも同じ並びになる数値を回文数とよぶことにします。この回文数について以下の問いに答えなさい。

問い1

5を掛けると回文数となる、3桁の数値のうち最大の数値を答えなさい。

できた。

>>> [x for x in range(100,1000) if `x*5` == `x*5`[::-1]]
[101, 103, 105, 107, 109, 111, 113, 115, 117, 119]

後から確認したら,清水川さんのコメント欄に書いてあるのと,ほぼ一緒でした。でも,コメント欄をさらに読み進めていくと,次のようにした方が速いと書かれています。

>>> (x for x in xrange(999,99,-1) if `x*5` == `x*5`[::-1]).next()
119

たしかに今回は3桁だからいいけど,もっと大きな桁数になった場合は,いちいちリストを生成せずにジェネレータ式を使った方が効率がいいですね。ジェネレータオブジェクトは,遅延評価なので値が必要になった時にしか生成されません。

勉強になるなぁ。ぼくのアタマも少しだけマルくなりました。

[Python] Setの積は元から定義されていた

昨日の Rangeの積を求める なんですが, set のベースクラス BaseSet の定義を見てみたらこう書かれていました。

def __and__(self, other):
    """Return the intersection of two sets as a new set.
     (I.e. all elements that are in both sets.)
    """
    if not isinstance(other, BaseSet):
        return NotImplemented
    return self.intersection(other)

ということは,Set型は元から a & b という書き方ができるんですね。実際に試してみると,とても簡単に集合の積がとれました。

>>> a = range(1,7); b = range(3,10); c = range(4,12)

>>> print a,b,c
[1, 2, 3, 4, 5, 6] [3, 4, 5, 6, 7, 8, 9] [4, 5, 6, 7, 8, 9, 10, 11]

>>> set(a) & set(b)
set([3, 4, 5, 6])

>>> set(a) & set(b) & set(c)
set([4, 5, 6])

終了──── しかも,RubyのRangeって数値以外も扱えるらしいじゃないですか。
全然だめだ>自分

気を取り直して,list型に「 & 」の振る舞いを実装してみることにします。元のlist型には「 & 」は定義されていないので,当然ながら「 a & b 」という表記はエラーになります。

>>> a = [1,2,3]; b = [2,3,4]; c = [3,4]

>>> a & b
Traceback (most recent call last):
  File "", line 1, in 
TypeError: unsupported operand type(s) for &: 'list' and 'list'

& 演算子は,__and__メソッドを定義することで利用可能になるので,新たに list を継承した xlist クラスを作ります。

class xlist(list):
    def __and__(self, other):
        return xlist(filter(lambda x: x in other, self))
実行してみましょう。
>>> a = xlist([1,2,3,4]); b = xlist([2,3,4,5]); c = xlist([4,5,6])

>>> a & b
[2, 3, 4]

>>> a & b & c
[4]

できた。

り, Reduce 最高

[Python] Rangeの積を求める

ueBLOGさんのブログ経由で知ったこの Range の積を求めるというもの。

» [Ruby] Rangeの積を求める - masuidrive
» Life is beautiful: 教えながら学ぶRuby:「Rangeの積を求める」をやってみた

を Python で書いてみました。引数に3個以上とかのRangeを渡されても大丈夫です。
元ネタの Ruby は Range クラスを拡張していますが、 Python の Range はビルトイン関数なので関数定義で。

from sets import Set
def range2(*args):
    return reduce(Set.intersection, map(Set, args))

では、実行してみましょう。

>>> range2([1,2,3,4,5,6], [3,4,5,6,7,8,9], [4,5,6,7,8,9,10,11])
[4, 5, 6]
>>> range2([1,2,3,4,5,6], [3,4,5,6,7,8,9], [10,11])
[]
>>> range2(range(1,8), range(3,7), range(4, 200))
[4, 5, 6]

で、何が言いたいかというと、「Reduce なくさないでよ!」ということです。functools.reduce という感じで残るみたいですが、組み込み関数じゃなくなるのは悲しいなぁ。

便利べんり。 Reduce 最高。

Re: リスト内包表記キタコレ

a2cさんのブログに書いてあった Python に関するこの問題。
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
の配列を、リスト内包表記を使って次のように変換せよ。
[1, 2, 3, 4, 5, 6, 7, 8, 9]

前もって構造が分かっているという前提だと、こんな感じでしょうか。
List Comprehension を二重にするだけ。

>>> [x for y in arr for x in y]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
reduce()を使っていいならば、こっちのほうが自分は好きかも。
2.6からは使えなくなるみたいですが。
>>> reduce(lambda a,b: a+b, arr)
[1, 2, 3, 4, 5, 6, 7, 8, 9]

リストが何重の入れ子になっているか分かっていない場合は、 List Comprehension だけでできるのかなぁ… 分かりません、誰か教えてください。