PyAudioの使い方まとめ
音声入出力ライブラリであるPyAudioの使い方をまとめた記事です。
PyAudioの基本メモ
PyAudioの基本メモ1 - たけし備忘録
PyAudioの基本メモ2 音声入出力 - たけし備忘録
PyAudioとpyatgraphでリアルタイムプロット
pyqtgraph+PyAudioによるリアルタイムで音声プロット - たけし備忘録
pyqtgraph+PyAudioによるリアルタイムで音声プロット その2 - たけし備忘録
PyODE+VisualPythonで物理シミュレーション 目次
一度はやってみたい物理シミュレーション
物理シミュレーションといえば物理演算エンジン
色々な種類があります。
今回はその中でもPythonでバインディングされているC++の物理エンジンライブラリであるODE(OpenDynamicsEngine)を用いてシミュレーションをしてみます。
参考文献
ODE関連のサイト
DEMURA.NET(日本語)
C++ライブラリでのODEの丁寧な解説ODEプログラミング解析so-zou.jp(日本語)
C++ライブラリでのODEの図ありの丁寧な解説PyODE(英語)
ODEのPythonバインディングであるPyODEの公式サイト
API Referenceをよく見る
VisualPython関連のサイト
VPython(英語)
VisualPythonの公式サイトVisualモジュールVPython(日本語)
VPythonで主に使用する関数やオブジェクトの日本語解説 ありがたい画像処理についてあれこれ: VPython
シンプルなコードが多く、辞書的でわかりやすい。テクスチャや光源の扱い方も載ってるのでとても助かる。
基本を学ぶ
Julia+SymPyの勝手なまとめ
自分の気になったところだけメモしていく形です
基本的にはJuliaのSymPyパッケージ内に入っているtutorial.mdというファイルから抜粋する形です。
SymPy の導入
まずはjuliaを立ち上げてSymPyのパッケージをインストールしましょう。
PyCallに依存しているので入れてない方はPyCallもインストールしましょう。
$ julia _ _ _ _(_)_ | A fresh approach to technical co (_) | (_) (_) | Documentation: http://docs.julia _ _ _| |_ __ _ | Type "?help" for help. | | | | | | |/ _ | | | | |_| | | | (_| | | Version 0.4.3 (2016-01-12 21:37) _/ |\__'_|_|_|\__'_| | Official http://julialang.org/ r |__/ | x86_64-w64-mingw32 julia> Pkg.add("PyCall") ...........なんかいろいろ出る julia> Pkg.add("SymPy") ...........なんかいろいろ出る julia>
<*追記*>
依存がPyCallとSymPyだけじゃありませんでした。
JuliaのPyCallとSymPyパッケージを入れた環境に、Python(2でも3でもいい)をインストールし、かつPythonのSymPyライブラリをインストールする必要があります。
python.jp
こちらのPython日本語ホームページからダウンロードできます。バージョンは2でも3でもお好きな方で大丈夫です。
Pythonのインストールが終わったら、次はPythonのSymPyをインストールする必要があります。
Pythonは2.7.9以上のバージョン(3を含む)ならば、PIPというパッケージ管理ツールが同梱していますのでそのままお使いいただけます。
$ python -m pip install sympy
で基本的にはインストールできます。
- 上記でインストール出来ない場合(Windowsのみ記載)
上記の方法でインストール出来ない場合、次の非公式パッケージがダウンロードできるサイトで.whlというファイルをダウンロードしましょう。
Python非公式パッケージ
現時点(2016/1)ではsympy-0.7.6.1-py2.py3-none-any.whlが最新のようです。
この.whlファイルを、ターミナルから操作しやすいディレクトリに入れておきましょう。
今回の場合、C:\test\sympy-0.7.6.1-py2.py3-none-any.whlとして保存しておくことにします。
$ pwd # 現在地 C:\test $ ls sympy-0.7.6.1-py2.py3-none-any.whl $ python -m pip install sympy-0.7.6.1-py2.py3-none-any.whl (色々出る)
で完了です。
- 上記でインストール出来ないかつ不安だからpython2と3の両方インストールしちゃったよの場合(Windowsのみ記載)
pythonはデフォルトで2と3が共存できます(3の方が新しいですが2への後方互換性が無いです)。
そのような場合 pyコマンドで2と3を明示的に切り替えることが出来ます。
# Python2を使う場合 $ py -2 -m pip install sympy-0.7.6.1-py2.py3-none-any.whl # Python3を使う場合 $ py -3 -m pip install sympy-0.7.6.1-py2.py3-none-any.whl
シンボルの生成
SymPyのJuliaでのラッパは色々なシンボルの生成の仕方があります。
1つずつシンボルを生成
julia> x = Sym("x") # Sym関数での生成 x julia> @syms x # symsマクロでの生成 (x,) julia> x x
複数のシンボルを一気に生成
julia> x, y, z = symbols("x, y, z") # symbols関数での生成 (x,y,z) julia> a, b, c, d, e = symbols("a:e") # ":"というイテレータで一気に生成 (a,b,c,d,e) julia> @syms x y z # symsマクロで生成 (x,y,z)
マクロでの生成が一番手軽でよさそう
特殊な定数 PI, E, oo
PIは円周率
Eは自然定数の底(ネイピア数)
ooは無限大です
julia> PI,E,oo
(pi,E,oo)
juliaはデフォルトでpiという定数がありますがPIとは異なります。
julia> [asin(1), asin(Sym(1))] 2-element Array{SymPy.Sym,1} [1.5707963267949] [ ] [ pi ] [ -- ] [ 2 ]
代入
シンボルで定義した式に、数値またはシンボルを代入します。
Julia固有の色々な代入の仕方があります。
subs関数による代入
前準備
julia> @syms x y (x,y) julia> f = x^2+2x+1 2 x + 2*x + 1
シンボルxにシンボルyを代入
julia> subs(f, x, y) 2 y + 2*y + 1
シンボルxに数値1を代入
julia> subs(f, x, 1) 4
便利な代入
前準備
julia> @syms x y z
(x,y,z)
julia> f=x+y+z
x + y + z
便利な代入1
これは便利な気がする
julia> f(x=>1, y=>pi) z + 1 + pi
便利な代入2
代入の順序がよくわかんない
julia> f(1, pi) y + 1 + pi
シンボルから数値への変換
evalf関数とN関数の二つの方法があります。
NはBigFloatという型らしいです。よく知りません。
evalfはお馴染みです。
julia> evalf(PI) 3.14159265358979 julia> N(PI) 3.141592653589793 julia> evalf(PI, 30) # 桁数指定 30桁 3.14159265358979323846264338328 julia> N(PI, 30) # 桁数じゃなかった。何者だろうこの引数は 3.1415926535897932384626433832793
方程式の解
solve関数を使います。
前準備
julia> @syms x (x,) julia> f=x^2+x+1 2 x + x + 1
解を得る1 x^2+x+1=0
julia> solve(f) 2***element Array{SymPy.Sym,1} [ ___ ] [ 1 \/ 3 *I] [- - - -------] [ 2 2 ] [ ] [ ___ ] [ 1 \/ 3 *I] [- - + -------] [ 2 2 ]
解を得る2 x^2+x+1=1
julia> solve(Eq(f, 1)) 2-element Array{SymPy.Sym,1} [-1] [ ] [0 ]
解を得る3 x^2+x+1=0
julia> solve(f⩵0) 2-element Array{SymPy.Sym,1} [ ___ ] [ 1 \/ 3 *I] [- - - -------] [ 2 2 ] [ ] [ ___ ] [ 1 \/ 3 *I] [- - - -------] [ 2 2 ] # ※注意!! f==0と書いていますがこれは \Equalの後にTabを押して出る特殊記号です。
極限
極限はlimit関数で操作できます。
基本の計算方法
julia> @syms x h (x,h) julia> limit(sin(x)/x, x, 0) 1 julia> limit(sin(x)/x, x=>0) 1 julia> limit((1+1/x)^x, x=>oo) E julia> limit((sin(x+h)-sin(x))/h, h=>0) cos(x)
数値計算
やっぱりなんだかんだ数値計算が出来てなんぼさ。
ということで数値計算の主な方法です。
関数の定義
Juliaでの関数の定義はいろいろなやり方があります。
まずSymPyを使うとシンボルを定義します。
シンボルはSymPy.Sym型の変数ですのでJuliaの性質である多重ディスパッチが使えます。
多重ディスパッチとは、同名の関数、例えばtestという関数を
function test(x::Int) return x end function test(x::Float64) return 2x end
として同名で、引数の型の違いによって出力や内容を変える性質のことです。
多重ディスパッチを使うと、
@syms x f(x) = x^2+x+1
という風に定義すると
julia> f(x) 2 x + 2*x + 1 julia> f(1) 4 julia> f(1.0) 4.0 julia> f(1:10) ERROR: MethodError: `*` has no method matching *(::UnitRange{Int64}, ::UnitRange{Int64}) Closest candidates are: *(::Any, ::Any, ::Any, ::Any...) *{T}(::Bidiagonal{T}, ::AbstractArray{T,1}) *(::Number, ::AbstractArray{T,N}) ... in power_by_squaring at intfuncs.jl:78 in f at none:1
1:10を引数にするとエラーが出ました。
そこでArray型にも対応できるように
f(x) = x.^2+2x+1
とします。 x^2がx.^2になっただけです。
このようにすれば
julia> f(1:10) 10-element Array{Int64,1}: 4 9 16 25 36 49 64 81 100 121
となります。
行列も引数に与えられます。
SymPyのままでも
@syms x f = x.^2+2x+1
としても
julia> f(x) 2 x + 2*x + 1 julia> f(1) 4 julia> f(1.0) 4.00000000000000 julia> f(1:10) ERROR: MethodError: `convert` has no method matching convert(::Type{SymPy.Sym}, ::UnitRange{Int64}) This may have arisen from a call to the constructor SymPy.Sym(...), since type constructors fall back to convert methods. Closest candidates are: SymPy.Sym(::Any) SymPy.Sym(::Any...) call{T}(::Type{T}, ::Any) ... in subs at C:\Users\takeshi\.julia\v0.4\SymPy\src\subs.jl:46 in call at C:\Users\takeshi\.julia\v0.4\SymPy\src\subs.jl:115
とこのように関数のように使うことはできます。
しかし1:10などの配列や行列などは代入できません。
この理由としては
f = x.^2+2x+1
と定義するとSymPy.Sym型であり
f(x) = x.^2+2x+1
と定義するとこれは多重ディスパッチによって無名関数になるからです。
型を確認してみましょう。
区別がつきやすいように
@syms x f(x) = x.^2+2x+1 g = x.^2+2x+1
としておきます。
julia> typeof(f)
Function
julia> typeof(g)
SymPy.Sym
fがFunction型、gがSymPy.Sym型になっています。
またさらにfの場合
julia> typeof(f(x)) SymPy.Sym julia> typeof(f(1)) Int64 julia> typeof(f(1.0)) Float64 julia> typeof(f(1:10)) Array{Int64,1}
となります。
gの場合は
julia> typeof(g(x)) SymPy.Sym julia> typeof(g(1)) SymPy.Sym julia> typeof(g(1.0)) SymPy.Sym
となっていずれもSympy.Sym型になります。
なかなかこれが使えます。
微分
当たり前ですがPythonのSymPyと同様に記号微分が出来ます。
julia> @syms x (x,) julia> f(x) = x.^2+2x+1 f (generic function with 1 method) julia> diff(f(x)) 2*x + 2 julia> diff(f(x), x) 2*x + 2 julia> diff(f) 2*x + 2
diff関数は多重ディスパッチで
diff(f:SymPy.Sym)だけでなく
diff(f::Function)も定義されているので、無名関数として定義したfを入れても微分してくれます。
diff関数のオプション
diff関数は任意の回数だけ微分することができます。
以下に例を書きます。
julia> f(x) 2 x + 2*x + 1 julia> diff(f(x), x, 0) # 0階微分 2 x + 2*x + 1 julia> diff(f(x), x, 1) # 1階微分 2*x + 2 julia> diff(f(x), x, 2) # 2階微分 2
もちろんfのままでも渡せます。が、少し文法が異なります。
要するにxが消えます。無名関数のまま渡すので、引数の情報がいらないわけです。
julia> f(x) 2 x + 2*x + 1 julia> diff(f, 0) # 0階微分 2 x + 2*x + 1 julia> diff(f, 1) # 1階微分 2*x + 2 julia> diff(f, 2) # 2階微分 2
偏微分
2つのシンボルで定義された関数は偏微分できます。
さっそく例を出していきましょう。
julia> @syms x y (x,y) julia> f(x, y) = x^2 + y^2 + x*y f (generic function with 2 methods) julia> diff(f(x,y), x) # xについて偏微分 2*x + y julia> diff(f(x,y), y) # yについて偏微分 x + 2*y julia> diff(f(x,y), x, y) # x,yについて偏微分 1 julia> diff(f(x,y)) ERROR: PyError (:PyObject_Call) <type 'exceptions.ValueError'> ValueError('\nSince there is more than one variable in the expression, the\nvariable(s) of differentiation must be supplied to differentiate x**2\n+ x*y + y**2',) File "C:\Python27\lib\site-packages\sympy\core\function.py", line 1638, in diff return Derivative(f, *symbols, **kwargs) File "C:\Python27\lib\site-packages\sympy\core\function.py", line 987, in __new__ must be supplied to differentiate %s''' % expr)) [inlined code] from C:\Users\takeshi\.julia\v0.4\PyCall\src\exception.jl:81 in pycall at C:\Users\takeshi\.julia\v0.4\PyCall\src\PyCall.jl:361 in fn at C:\Users\takeshi\.julia\v0.4\PyCall\src\conversions.jl:194 in call_sympy_fun at C:\Users\takeshi\.julia\v0.4\SymPy\src\SymPy.jl:262 in sympy_meth at C:\Users\takeshi\.julia\v0.4\SymPy\src\SymPy.jl:268 in diff at C:\Users\takeshi\.julia\v0.4\SymPy\src\math.jl:190 julia> diff(f) # 無名関数を偏微分 2*x + 2
積分
不定積分
julia> f(x) 2 x + 2*x + 1 julia> integrate(f(x), x) 3 x 2 -- + x + x 3 julia> integrate(f(x)) 3 x 2 -- + x + x 3 julia> integrate(f) 3 x 2 -- + x + x 3
より一般的な書き方
julia> @syms x n (x,n) julia> integrate(x^n, x) /log(x) for n = -1 | | n + 1 <x |------ otherwise |n + 1 \
めちゃめちゃわかりにくいですがこれは
ということです。
第n部分和と無限級数
基本的な使い方
まずは基本からです。summation関数を使います。
julia> @syms k n (k,n) julia> summation(2^k, (k, 1, n)) # 第n部分和 n + 1 2 *** 2 julia> summation(1/k^2, (k, 1, oo)) # 無限級数(この例はゼータ関数) 2 pi --- 6
PyAudioの基本メモ2 音声入出力
PyAudioの基本メモ1の続きです。
今回はPyAudioの基本的な使い方を書きます。
ほとんどPyAudio: PortAudio v19 Python Bindingsの例題のままです。
音声の出力
import pyaudio import wave CHUNK = 1024 filename="好きなwavファイル" wf = wave.open(filename, 'rb') p = pyaudio.PyAudio() stream = p.open(format=p.get_format_from_width(wf.getsampwidth()), channels=wf.getnchannels(), rate=wf.getframerate(), output=True) """ format : ストリームを読み書きするときのデータ型 channels: ステレオかモノラルかの選択 1でモノラル 2でステレオ rate : サンプル周波数 output : 出力モード """ # 1024個読み取り data = wf.readframes(CHUNK) while data != '': stream.write(data) # ストリームへの書き込み(バイナリ) data = wf.readframes(CHUNK) # ファイルから1024個*2個の stream.stop_stream() stream.close() p.terminate()
これで好きなwavファイルを再生できる
音声の入力
import pyaudio import wave CHUNK = 1024 FORMAT = pyaudio.paInt16 # int16型 CHANNELS = 2 # ステレオ RATE = 44100 # 441.kHz RECORD_SECONDS = 5 # 5秒録音 WAVE_OUTPUT_FILENAME = "output.wav" p = pyaudio.PyAudio() stream = p.open(format=FORMAT, channels=CHANNELS, rate=RATE, input=True, frames_per_buffer=CHUNK) print("* recording") frames = [] for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)): data = stream.read(CHUNK) frames.append(data) print("* done recording") stream.stop_stream() stream.close() p.terminate() wf = wave.open(WAVE_OUTPUT_FILENAME, 'wb') wf.setnchannels(CHANNELS) wf.setsampwidth(p.get_sample_size(FORMAT)) wf.setframerate(RATE) wf.writeframes(b''.join(frames)) wf.close()
frames_per_bufferがよくわからん
とりあえず1024にしておけば大丈夫そう
リアルタイムで音声入出力
マイク入力した音声をリアルタイムでスピーカーから出力します。
マイクはOSで設定したデフォルト、スピーカーもOSで設定したデフォルトの機器を使います。
※注意! イヤホンをしていないとハウリングして耳がキィーンとします。
# -*- coding:utf-8 -*- import pyaudio CHUNK=1024 RATE=44100 p=pyaudio.PyAudio() stream=p.open( format = pyaudio.paInt16, channels = 1, rate = RATE, frames_per_buffer = CHUNK, input = True, output = True) # inputとoutputを同時にTrueにする while stream.is_active(): input = stream.read(CHUNK) output = stream.write(input) stream.stop_stream() stream.close() p.terminate() print "Stop Streaming"
リアルタイムで音声加工
マイク入力した音声をリアルタイムで加工して出力します。
# -*- coding:utf-8 -*- import pyaudio CHUNK=1024*2 RATE=44100 p=pyaudio.PyAudio() stream=p.open( format = pyaudio.paInt16, channels = 1, rate = RATE, frames_per_buffer = CHUNK, input = True, output = True) # inputとoutputを同時にTrueにする def audio_trans(input): # なんかしらの処理 return ret while stream.is_active(): input = stream.read(CHUNK) input = audio_trans(input) output = stream.write(input) stream.stop_stream() stream.close() p.terminate() print "Stop Streaming"
加工する場合はCHUNKを2倍の2048にして少し処理を遅くしました。
なぜならばまず、アウトプットする時のストリームへの書き込みに必要となる時間がCHUNK=1024とすると
(書き込みに必要な時間)=CHUNK/RATE=0.023[sec] でした。
timeモジュールで測定してみましたが確かにそのくらいの時間のようです。
ストリームから音声を読み取る時間と入力音声を加工する処理の時間の合計が、書き込みに必要な時間より遅いと
音声出力中→→→終了 | 空白の時間 | 音声出力...→→ |
読み取り→→→→加工 | 処理中......... | 書き込み |
↑
ここで空白の時間(音声が出ない→声が途切れて聞こえる)
という現象が起こりました。(わかりにく)
この空白の時間が人間が感じ取れないほど短い時間(またサンプル周期よりも小さい時間)であればプツプツ音は出ないようです。
また読み込みよりも書き込みのほうが圧倒的に時間がかかるようなのでCHUNKを大きくしても書き込み時間だけを気にしていれば平気そうです。
このため、CHUNKを2倍にして書き込みに必要な時間を 0.046[sec]としました。
読み取り時間+処理時間 がテキトーに処理を書いた(ピッチ抽出など)ときおよそ 0.03[sec]程度だったのでこれで空白の時間はなくなりました
が、入力から出力の遅れ時間は当たり前のごとく増えました。
適宜CHUNK幅を調整して遅れさせてください。
PyAudioの基本メモ1
PyAudioの使い方を時々忘れてしまうのでメモ書き
用語の名前は私が勝手に読んでいる名前もあるので一般的な呼び方では無いこともあります。
基本的な用語
●音源
基本的には全てバイナリデータ(16進数 0x13 0x76など)
●静的な音源
wavファイル, rawファイル, mp3ファイルなど
●動的な音源
マイクに現在入力している音声など
●wav, raw, mp3の違い
通常の静的な音源は
ヘッダ(サンプル周波数などのメタデータ)
+
ボディ(音源の本体)
という構成になっている。
rawファイル→ヘッダ無し, ボディ有り
wavファイル→ヘッダ有り, ボディ有り
mp3ファイル→ヘッダ有り, ボディ有り
htmlみたいなもんだと思っていいかもしれない。たまにフッタも付いてるやつもある。
●wavファイルとmp3ファイルの違い
wavファイルはrawファイルにヘッダを付けたもの
mp3ファイルは音源のある周波数(44.1kHz? 22.05kHzだったかな)以上の音をカットしてサイズ小さくしている。
まとめると
wavファイル→生音声
mp3ファイル→加工された音声(音楽聞けりゃオッケー程度)
●動的な音源からの読み込み
後述するチャンクというサイズごとに読み取る必要がある。
●静的な音源からの読み込み
チャンク毎に読み取ってもいいし、全部一気に読み取ってもOK。
●ストリーム
データストリームとも言う。ストリーミング方式の動画などがある。データの流れ。
音声で言うと、マイクからは常に音声データが流れて来ていて、ストリームに流れている。河みたいなものだと思えばいい。
ストリームに書き込むとは 河にデータを流すこと
ストリームを読み込むとは 河からデータを取ってくること
パラメータなどの用語
●チャンク(CHUNK)
音源から1回読み込むときのデータサイズ。1024(=2の10乗) とする場合が多い
●サンプル周波数
サンプルレートだとか、フレームレートとも言われる。よくfsとかsrと書く。次元は[個/sec]。
データを読み取るときに、何秒ごとに1点のデータを取ってくるかを決める値。
逆数はサンプル周期と言われTsなどと書く。
よく使われるのは 44.1kHz, 16kHzなど。
(例) fs = 44.1[kHz]の場合
1/fs=Ts=22.7[μsec]毎に1点データを取ってくる。
たまにナイキスト周波数とか言われることがあるけどナイキスト周波数はサンプル周波数の半分の周波数のこと(標本化定理)。
●フレーム数
少なくともPythonのwaveモジュール上ではバイナリデータの個数。
0x00 などが1024個入ってるデータは1024フレームと言う。
たぶん分野だとか動画だとかそういうジャンルによって使われ方が違う。
よくわかってない。
●音源の秒数の計算
音源の秒数の計算には
サンプル周波数 バイナリデータ数
の2つが必要。
(秒数)=バイナリデータ数/サンプル周波数
という計算で出せる。
(例) CHUNK個のデータをfsというサンプル周波数で取ってきた。
(秒数)=CHUNK/fs
読み込んだバイナリデータを数値に変換
マイクから音声を読み込んで、プロットする時の基本的な動きは
1. ストリームから音声をCHUNK(ここでは1024とする)の長さでバイナリ形式で読み込む
2. 読み込んだバイナリデータはCHUNKの2倍の長さの2048(罠!)
3. バイナリデータをint16型に変換
ただしint16型に変換するのが通常なだけでfloat64型などにも変換できる。意味は無い。
4. int16型に変換すると長さがCHUNKと同じになる
バイナリ2つ "0x16 0x08" などのセットで1つの値になる。
バイナリ1つは8bitなのでint16の16bit数値にするには2つ分必要。なので2048個のバイナリデータを先頭から2つずつint16型の数値に変換すると全体として1/2のサイズ、1024個のint16データになる。
意味は無いがfloat64型に変換すると8個ずつ読み込んでfloat64の数値にするので2048個の1/8のサイズになる。
5. int16に変換した1024個のデータをプロット
フィルタなどを掛けるときはint型に戻してからのほうがPythonでは扱いやすい(そもそもバイナリのままバイナリとして扱えるのか?)
Pythonでtreeコマンド実装
Windowsにもtreeコマンドがありますがなんとも気に入らなかったので自分で使う用にtreeコマンドを実装しました。
bashだとかCだとかでやったほうが日本語周りはかなり楽なんだろうけど、あえて日本語周りが大変なpythonで練習。
普段あんまりpythonで日本語扱うことが少ないのでいい機会かもしれない。
ということで獣のごとくテキトーに思うまま実装しました。保守性は皆無です。
コマンドプロンプトの文字コードはcp932で、Cygwinは確かめて無いので知りません。変えてないからデフォルトのままのはず。
以下よりソースコード
[tree.py]
#!/usr/bin/env python # -*- coding:utf-8 -*- import os import sys def print_enc(str): try: print str except: print str.encode("utf-8") def tree(path = u".", d = 0, depth = 2, tab=u""): #深さの指定で再帰中断 if d==depth: return else: #指定path下(未指定でカレントディレクトリ)のフォルダとファイルを取得 file_list = [] dir_list = [] for p in os.listdir(path): if os.path.isfile(path+u"/"+p): file_list.append(p) if os.path.isdir(path+u"/"+p): dir_list.append(p) #ルートを表示 if d==0: print u"/%s" % os.getcwd().split("\\")[-1] #ファイルの表示 for i in xrange(len(file_list)): if i!=len(file_list)-1: print tab+u"┣━", print_enc(file_list[i]) else: if len(dir_list)==0: print tab+u"┗━", print_enc(file_list[i]) else: print tab+u"┣━", print_enc(file_list[i]) #ディレクトリの表示 for i in xrange(len(dir_list)): if i!=len(dir_list)-1: print tab+u"┣━", print_enc(dir_list[i]) tree(path = path+u"/"+dir_list[i], d=d+1, depth=depth, tab=tab+u"┃\t") else: print tab+u"┗━", print_enc(dir_list[i]) tree(path = path+u"/"+dir_list[i], d=d+1, depth=depth, tab=tab+u" \t") return if __name__=="__main__": if len(sys.argv)==2 and sys.argv[1]: tree(depth=int(sys.argv[1])) else: tree()
すんごい見づらいし汚い感じですが一応動きました。
ただ、使うターミナルの設定だとかlessを使った場合だとかで表示がかなり違うのでpythonだとめんどいなぁという印象。3系だと文字周りが簡単になったとか聞くけどどうなんだろうか。
とりあえず
- 標準モジュールだけで作成
- 日本語を表示できること(特殊文字は除く)
が実現できたのでいいかな
自分で使う用なのでexe化してしまってテキトーにpath通してしまえばいいや
使い方は(現時点では)
$python tree.py 3
という形で使います。
コマンドライン引数の3は表示するディレクトリの深さです。上の場合3階層まで表示します。1でカレントディレクトリ内を表示します。
デフォルトでは2になっています。
以下より様々な表示結果
[テスト用フォルダ]
[コマンドプロンプト(引数:デフォルト)]
python tree.py
[コマンドプロンプト(引数:1)]
python tree.py 1
[コマンドプロンプト(lessをパイプでつなげた状態)]
python tree.py | less
[コマンドプロンプト(引数:4)]
python tree.py 4
[Cygwin(引数:デフォルト)]
python tree.py
[Cygwin(lessをパイプでつなげた状態)]
python tree.py | less
lessをつなげたときだけなぜか特殊文字の♡まで表示出来たのはなんでだろう。しかもコマンドプロンプトの時だけ。
lessコマンドは双方ともCygwin内蔵のlessから持ってきているので文字コードの違いなんだろうなきっと。
コマンドとして使うときディレクトリ指定もできたらいいのですがコマンドライン引数のなんちゃらが面倒でした。
調べた感じだと組み込みでargparseというモジュールがあるらしいのでいずれいじってみたいです。
めんどうだからここまでで終わりにしました。
Bottle日本語ドキュメント(自分用) 記事一覧まとめ
チュートリアル
この記事は、下記の情報を訳したものです。
Tutorial — Bottle 0.13-dev documentation
このチュートリアルでは、ボトルのWebフレームワークの概念と機能を紹介し、同様に基本的かつ高度なトピックをカバーしています。あなたが最初から最後までそれを読んで、またはそれ以降のリファレンスとして使用することができます。自動的に生成されたAPIリファレンスにも、あなたにとっては興味深いかも知れません。
それ以上の詳細について説明しますが、このチュートリアル未満を説明しています。最も一般的な質問のためのソリューションは、当社のレシピ集やFAQページに記載されています。何か助けが必要な場合は、私たちのメーリングリストに参加したり、私たちのIRCチャンネルで私たちをご覧ください。
- 2.クイックスタート - たけし備忘録
- デフォルトアプリケーション
- 6.テンプレート - たけし備忘録
- 構文
- キャッシング
- 9.展開と用語集 - たけし備忘録
- 展開
- 用語集