Python プログラミング

Python のプログラミングはなかなか楽しい。海外では結構人気が あるらしい。Perl よりは綺麗に書けるし、ライブラリも豊富。 使わない手はない。Python の人気は高まりつつある。

Contents

ビルトイン型

ビルトイン型一覧

内容
数値
int 整数
long Long型整数
float 浮動小数点
complex 複素数
文字列
str 文字列
unicode Unicode文字列
データ構造
tuple タプル
dict 辞書
list リスト
オブジェクト指向
object オブジェクト。全てのビルトイン型およびクラスの祖先。 祖先をたどればすべてが object。
type クラスオブジェクトの型。メタクラス。type の インスタンスがクラスオブジェクト。クラスのクラス。 メタクラスと親クラスは違う。
クラス属性の型
classmethod クラスメソッド
staticmethod 静的メソッド
property プロパティ。読み出し専用。
その他
file ファイルオブジェクト
super スーパークラスオブジェクトの呼び出し。 「型」と呼べるのかどうか疑問が残る。

メタクラスプログラミング

C++ のクラスと Python のクラス

C++ と Python の大きな違いは、前者がコンパイラ向け、 後者がインタプリタ向けの言語であるということ。あたりまえだけど。

C++ では「クラス」はあくまで、ヘッダファイルなどでの「定義」であって、 コンパイラにかけるときには、実際にその定義されたコードが実行される ことはない。これもあたりまえ。

一方、Python はインタプリタなので、「クラス」文はいきなり実行されている。 もうちょっと具体的に言うと、:

1:    class foo(object):
2:      def bar(self):
3:        print 'Hello, world!!'
4:
5:    x = foo()
6:    x.bar()

上記のような Python のプログラムがあったとき、C++ の感覚だと、 5行目から実行されているような気がする。で、foo() で foo クラスの を作るときに、やっと1行目から3行目の文が実行されるもの、と なんとなく思っていたのだけれど、そう考えるといまいち理解が すすまなかった。

Python はインタプリタなので、やっぱり1行目から実行していく。 じゃあ、1行目から3行目まで実行してどうなるのか? もちろん 'Hello, world!!'と出力するわけではない。

インタプリタの気持ちになってみる。

  1. 1行目、class foo で、foo という名前にこれから作るクラスオブジェクトを 結びつけよう。

  2. 1行目、(object)で、このスーパークラスは object だとわかったので、 スーパークラスのタプルに入れとこう。

  3. 2行目、とりあえず、一時的に辞書を作って bar という key に、これから 作る関数オブジェクトを結びつけよう。

  4. 3行目、print 'Hello, world' で関数オブジェクトを作ろう。

  5. ?行目、クラスの名前'foo'とスーパークラスのタプル(object,)と辞書 { 'bar' : <関数オブジェクト> }で、メタクラス(この場合はtype)を 呼び出す。こんな感じ:

    foo = type( 'foo', (object,), { 'bar' : <関数オブジェクト> } )
    

    これで、foo にクラスオブジェクトが結合される。

「クラスオブジェクト」を生成して、それを foo という 名前に結合する。これが、1行目から3行目を実行したときに生じる 事態だと思われる。

class 文を使わないでクラスオブジェクトを作る

先の type 型を使えば、class 文を使わずとも、クラスオブジェクトを つくることができる。:

########################################################################
###
### クラス文を使って、クラス・オブジェクトを生成する
### 普通のやり方。
###

##
## class文の実行終了時にクラス・オブジェクトが 'TestClass1' という名前に
## 結び付けられる。
##
class TestClass1(object):
        def hello(self):
                print 'Hello, world!!'

testInst1 = TestClass1()
testInst1.hello()               ## Hello, world と出力


########################################################################
###
### type 型を使って、クラス・オブジェクトを生成する
### 特殊なやり方。
###

def printHello(self):
        print 'Hello, world!!'

##
## type()で生成されたクラス・オブジェクトが 'TestClass2' という名前に
## 結び付けられる。
##
TestClass2 = type(
        'TestClass2',
        ( object, ),
        { 'hello': printHello }
)

testInst2 = TestClass2()
testInst2.hello()                ## Hello, world と出力

この例のように、type 型はクラス・オブジェクトを作る クラス(型)なので、メタクラスなどと呼ばれる。

自分で作るメタクラス

自分でもメタクラスを作ることができる。もっとも簡単なのが type を継承したクラスをつくればよいのである。

じゃあ、どうやればこの自作メタクラスを、クラス・オブジェクトの 生成に使うのかと言えば、属性 __metaclass__ でメタクラスを 入れておけばよい。

次は自作メタクラスの例。以下、例が長いので、先に解説。 サンプルプログラムの要は、:

class TestClass1(object):
        __metaclass__ = metaTestClass

class TestClass2(object):
        __metaclass__ = metaTestClass

と、定義(?)がまったく同じ二つのクラスだけれど、:

x = TestClass1()
x.say()                       ## YES と出力する

y = TestClass2()
y.say()                       ## NO と出力する

実行するとインスタンスの振る舞いが異なっているというところが、 以下のサンプルプログラムのみそ。

プログラム全部は以下。:

## とりあえず、yes っていう変数(名前)への代入(結合)。
##
yes = True

class metaTestClass(type):

        def __new__(cls, classname, classbases, classdict):

                ##
                ## say_yes と say_no の2つの
                ## 関数(オブジェクト)の定義
                ##
                def say_yes(self): print 'Yes'

                def say_no(self): print 'No'

                ##
                ## クラスの辞書の'say'という属性に
                ## 関数オブジェクトを結合(代入)する。
                ## ただし、say_yes を結合するか、
                ## say_no を結合するかは yes という
                ## 変数の値で決まる。
                ##
                if yes:
                        classdict['say'] = say_yes
                else:
                        classdict['say'] = say_no

                ##
                ## いじった辞書で「クラスオブジェクト」を
                ## 生成する。
                ##
                return type.__new__(cls, classname, classbases, classdict)

##
## クラスオブジェクト TestClass1 の生成。
## 生成にはメタクラス metaTestClass が使われる。
##
class TestClass1(object):
        __metaclass__ = metaTestClass

##
## yes の値を変えて、metaTestClass による
## クラスオブジェクトの生成の振る舞いを変更する。
##
yes = False

##
## クラスオブジェクト TestClass2 の生成。
## 生成にはメタクラス metaTestClass が使われる。
##
class TestClass2(object):
        __metaclass__ = metaTestClass


##
## TestClass1 のインスタンスの生成。
## TestClass1 の定義には 'say' という関数はないが、
## TestClass1 のクラスオブジェクト生成時に、'say' という
## 属性値に 'say_yes' の関数オブジェクトが結合されている
## ので、say() で呼び出し可能。
##
x = TestClass1()
x.say()                       ## YES と出力する

##
## TestClass2 のインスタンスの生成。
## TestClass2 の定義には 'say' という関数はないが、
## TestClass2 のクラスオブジェクト生成時に、'say' という
## 属性値に 'say_no' の関数オブジェクトが結合されている
## ので、say() で呼び出し可能。
##
y = TestClass2()
y.say()                       ## NO と出力する

メタメタクラス

もう、絶対必要ないけど、メタメタクラス(メタクラスのメタクラス)だって 一応つくれる。:

class metaMetaTest(type):

        def __new__(cls, name, bases, dict):

                def classgen(cls_, name_, bases_, dict_):
                        def hello(self): print 'Hello, world'
                        dict_['hello'] = hello
                        return type.__new__(cls_, name_, bases_, dict_)

                dict['__new__'] = classgen
                return type.__new__(cls, name, bases, dict)

class metaTest(type):
        __metaclass__ = metaMetaTest

class Test(object):
        __metaclass__ = metaTest

x = Test()
x.hello()               ## Hello, world と表示

実用的メタクラス例:Singleton

本当に役立つプログラム例として、Singleton パターンを示す(ただし、 Cookbook から拾ってきた)。これは実用的。:

class Singleton(type):

        ## クラス(オブジェクト)生成時に呼ばれる
        ##
        def __new__(self, name, bases, dict):

                ## 属性 instances を設定
                ##
                dict['instances'] = {}
                return type.__new__(self, name, bases, dict)

        ## クラス(オブジェクト)のインスタンス生成時に呼ばれる
        ##
        def __call__(self, *args):

                ## 新たな引数でクラスオブジェクトが呼ばれたら
                ## 新たなインスタンスを登録
                ##
                if not args in self.instances:
                        self.instances[args] = type.__call__(self, args)

                ## 登録されているインスタンスを返す
                ##
                return self.instances[args]


class Test(object):
        __metaclass__ = Singleton

        def __init__(self, arg): pass



x = Test(0)
y = Test(1)          ## y は x と違うインスタンス
z = Test(0)          ## z は x と同じインスタンス

x.attr = 1
y.attr = 2
z.attr = 3

assert x.attr == 3
assert y.attr == 2
assert z.attr == 3

日本語プログラミング

python の 2.4 では、デフォルトで日本語を扱うことができる。 しかし、色々とプログラミング作法を覚えておかないといけない。

日本語を取り扱う場合、次の三つの局面がある。

  1. 日本語文字列の外部入力
  2. 日本語文字列の内部処理
  3. 日本語文字列の外部出力

このうち 2 の「内部処理」については、python では Unicode を使うのが自然だし、プログラミングが楽だと思う。

そうすると、1 については、「日本語文字列をいかにUnicodeに変換するか」 3 については、「Unicodeをいかに日本語文字列に変換するか」 というポイントを押さえておけばよいかと思う。

基本の文字列

Python には、文字列とUnicode文字列があり、この二つは違う型として 取り扱われるので、ごっちゃにしないように注意する。

種類 文字列リテラル
文字列 'Hello, world!!'
Unicode文字列 u'Hello, world!!'

Shift JIS とか EUC JP とかの文字列は、もちろんUnicode文字列ではなく、 単なる文字列としてしか扱われない。単なるバイト列である。

コーディング

Python が日本語文字列を単なるバイト列として扱ってくれるのだが、 デフォルトでは問題が多い。

それはシステムのデフォルトコーディングが通常 'ascii' に設定されているため、 扱える文字(バイト)が 0 〜 127 までしかない。文字列などのデータに Shift JIS などの 8 bit のコードが入っていると、その文字列をunicodeに 変換したりしようと企んだ瞬間に、例外をあげられて、 あえなくプログラムは中断ことになりかねない。

以下に、「日本語でーす。」という文字列を4種、デフォルトコーディングが 'ascii'と'euc-jp'の2つの場合で分類して、その中身をまとめてみた。

  デフォルト コーディング プログラム 中身
1 ascii '日本語でーす。' EUC JP 文字列
2 u'日本語でーす。' 滅茶苦茶
3 '日本語でーす。'.decode('euc-jp') Unicode文字列
4 unicode('日本語でーす。', 'euc-jp') Unicode文字列
5 euc-jp '日本語でーす。' EUC JP 文字列
6 u'日本語でーす。' Unicode文字列
7 '日本語でーす。'.decode('euc-jp') Unicode文字列
8 unicode('日本語でーす。', 'euc-jp') Unicode文字列

2つ目の文字列の中身が滅茶苦茶なのは、日本語のコーディングが何なのか 判別できていないのに、無理にUnicode文字列に変換しようとするためである。

一応なにかUnicode文字列ができても、これを出力しようとすると、 「へんな 8 bit 文字がはいっているぞ」といった例外が発生することになる。

デフォルトコーディングだけでは問題は解決しない

それではデフォルトコーディングを euc-jp なり、shift_jis に設定するには、 ファイルの一行目か、二行目で、:

# coding: euc-jp

もしくは、:

# coding=euc-jp

という一行を書いておけばよい。

だけど、いちいちファイルを保存するときに euc-jp とか、utf-8 とか いちいち指定しない。指定できるエディタを使う、とか、いつも Windows だから Shift JIS でいいや、というのは個人的にとってもヤダ。メモ帳でもviでも 編集できなきゃヤダ。プログラム以外のことで心配するのはヤダヤダ。

それに、外部からの入力、例えばファイルやデータベースから取得した 文字列が必ずこのデフォルトコーディングと一致してるなんてことは あり得ないじゃないですか、ね、そうでしょ。

というわけで、上記の 4 〜 8 は個人的になし。1 は Unicode 文字列に なってないから、python においては扱いづらい。もちろん、2 は論外。 で結局、:

'日本語でーす。'.decode('euc-jp')

もしくは、:

unicode('日本語でーす。', 'euc-jp')

のどちらかの処理を、必ず日本語と思わしき文字列にほどこしておかないと 安心できない。

日本語のコーディングを見分ける

じゃあ、ある単なる日本語と思われる文字列が euc-jp なのか shift_jis なのか、 どうやって見分けるのだろうか? で、色々と Web を調べたけれど こういう機能は標準ではないらしい。

kconv というモジュールが何年か前から使えるようなのだけれど、 ほとんどが C 言語で書かれていて、CGI とかで使うにはちょっと 使いづらい。

で、Perl の Jcode.pm をもとに作ったのが、これ( Jcode.py )。 ただし、日本語のコーディングを見分ける jcode::getcode() しか 実装していません。変換は標準ライブラリで可能です。

出力にも気を配る

次のプログラムを端末(日本語版PuTTY、文字セット EUC-JP、LANG=ja_JP.eucJP) で実行する。:

print unicode('日本語でーす。', 'euc-jp')

結果は、もちろん「日本語でーす。」と表示される。しかし、これを シェルのリダイレクトで、出力をファイルに落とそうとすると、:

UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-7: ordinal not in range(128)

とかいう例外を食らっておしまい。 それに、EUC-JPの端末で Unicode の文字列を出力しようとして 文字化けしないのも何故なのか。

どうも、python が出力(この場合 sys.stdout)のコーディングによって、 Unicode文字列を変換しようとしているようである。例えば、次の プログラムを実行したとき、:

import sys
print sys.stderr.encoding

結果は以下の通り。

出力先 結果
端末に出力 eucJP
ファイルにリダイレクト None

python は、端末に出力しようとした時は、出力先のコーディングを見て、 Unicode文字列を日本語(この場合 EUC JP)文字列に変換しようと試みて いる模様。

一方、ファイルにリダイレクトしようとしたときは、出力先の コーディングが None なので、デフォルトの 'ascii' で出力しようとして、 変換に失敗している。

ちなみに、環境変数 LANG を ja_JP.SJIS にすると、Shift JIS に変換 してくれる。

結論としては、Unicode文字列を出力するときには、出力先にも気を配らないと エラーを食らうことになりそうだ。

XMLパーサ

Python 2.4 で、原因不明だけれど、日本語の入った XHTML に対し、 minidom はダメ、pulldom はOKだった(XREA での結果はこれ jp-xmldom.cgi )。

C++によるPythonモジュール

boost ライブラリを使えば、C++ で作ったライブラリを python で 使うことができる。パフォーマンスの厳しいところは C++ で書いて、 ユーザインタフェースは pygtk で、とかね。

なにはともあれ Hello, world!!

とにかく文字列を出力する関数をC++で描いて、それをpythonから呼び出して みる。まず、C++のコード。ファイル名は boopy.cpp:

//
// boopy.cpp
//
#include <boost/python.hpp>
using namespace boost::python;


char const* say_yes()
{
    return "YES!!";
}

char const* say_no()
{
    return "No...";
}

BOOST_PYTHON_MODULE(boopy)
{
    def("yes", say_yes);
    def("no", say_no);
}

解説抜きでやりたいことがわかると思いますが...

で、これをコンパイルするわけですが、boost.python の公式ページには bjam 使え、bjam 使え、悪いことは言わん bjam 使え、って 書いてあります。でも bjam の使い方わかりません。 とりあえず、NetBSD-3.1 では以下の Makefile でコンパイルできます。:

TARGET      =       boopy.so

SOURCES =   boopy.cpp
OBJECTS =   boopy.o

CC  =       gcc
CXX =       g++
CFLAGS      =       -Wall -W -O2 -fPIC -DNO_DEBUG
CXXFLAGS=   -I/usr/pkg/include/python2.4 -Wall -W -O2 -fPIC -DNO_DEBUG
INCPATH     =       -I/usr/pkg/include
LINK        =       g++
LFLAGS      =       -shared
LIBS        =       -Wl,-R/usr/pkg/lib -L/usr/pkg/lib -lboost_python-mt -lpython2.4 -lm -lc

.SUFFIXES: .cpp

.cpp.o:
    $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<

all: $(TARGET)

$(TARGET): $(OBJECTS)
    -rm -f $(TARGET)
    g++ $(LFLAGS) -o $(TARGET) $(OBJECTS) $(LIBS)

clean:
    -rm -f $(OBJECTS) $(TARGET)

boopy.o: boopy.cpp

で、make すると boopy.so というファイルができる。で、いよいよ python から呼び出して見ましょう。とりあえず、boopy.so と同じ ディレクトリでpythonを起動。:

$ python2.4
Python 2.4.3 (#1, Feb 24 2007, 16:58:42)
[GCC 3.3.3 (NetBSD nb3 20040520)] on netbsd3
Type "help", "copyright", "credits" or "license" for more information.
>>> import boopy
>>> print boopy.yes()
YES!!
>>> print boopy.no()
No...

お、とりあえず、boopy っていうモジュールができたぞ。

CGIプログラミング

CGI といえば Perl と PHP が有名ですが、もちろん Python でも CGI の 作成は可能です。 XREA も python が CGI として使えます。

何がなくとも、まずは、デバッグ

CGI で一番困るのは「デバッグ」。エラーメッセージは出てこないし、 デバッガだって使えない。

そこで、cgitb というライブラリを使う。使い方はいたって簡単。:

import cgitb; cgitb.enable()

この一行を CGI スクリプトのなるべく頭の方に一行書いておく。 XREA で以下の CGI スクリプトを動かす。:

#!/usr/local/bin/python
#
import cgitb; cgitb.enable()

raise Exception

動作例はここ( cgitb.cgi )をクリック。 一目瞭然、捕捉されない例外があがってもばっちり表示してくれる。 これで安心して CGI が書ける。