メイン

Python アーカイブ

2005年07月07日

メモ

Pythonで、MarkdownのファイルをHTMLに変換するプログラムを作成する予定。

2005年10月31日

PyInstaller: Python のスクリプトを Windows 用の実行ファイル (exe形式) に変換する

いやな日記 を参考に py2exe を使ってみると、hello.py を exe にしただけで distディレクトリのサイズは 2.04MB になった。 いやな日記 では 1.2MB と書かれている。なんでだろ?

Python スクリプトを Windows 用の実行ファイルに変換するソフトには py2exe の他に PyInstaller というのがあるらしい。 早速試してみた。

PyInstaller のページから PyInstaller 1.0 をダウンロードしてを展開する。

cd pyinstaller_1.0
python Configure.py

hello.py を作成する

print "hello, world"

実行ファイルを作成する

python Makespec.py hello.py
python Build.py ./hello/hello.spec

disthelloディレクトリのサイズは 1.41MB。

2006年11月26日

quoted-printableのエンコード

quopriモジュールを使うと、quoted-printableのエンコードができます。

#!python

import quopri

#エンコードするファイル
input = open('input.txt')
#エンコードした内容を保存するファイル
output = open('output.txt', 'w')
#空白文字やタブを変換するかどうか制御するフラグ
quotetabs = True
#エンコードする
quopri.encode(input, output, quotetabs)

Base64のエンコード

base64モジュールを使うと、Base64のエンコードができます。

#!python

import base64
#エンコードするファイル
input = open('input.txt')
#エンコードした内容を保存するファイル
output = open('b64.txt', 'w')
#エンコードする
for str in input.readlines():
    str = base64.b64encode(str)
    output.write(str)

2006年12月04日

PythonでFirebirdを使う

PythonでFirebirdを使う。

インストール

  1. PythonのFirebirdライブラリ KInterbasDB をダウンロードする。
    Pythonはバージョン2.5、Firebirdは1.5.3なので、kinterbasdb-3.2.win32-FB-1.5-py2.5.exeをダウンロードしました。

  2. ダウンロードしたファイルを実行して、インストールする。

以上でインストールは完了。

Firebirdの接続と切断

import kinterbasdb
kinterbasdb.init(type_conv=200)
#データベースに接続する
con = kinterbasdb.connect(dsn='localhost:C:/path/to/file.FDB',
                          user='sysdba',
                          password='masterkey',
                          charset="SJIS_0208")
#切断する
con.close()

SELECT文

cur = con.cursor()
cur.execute("select * from ADDRESS")
for row in cur:
  print "postcode = %s, address = %s" % (row[0], row[1])

INSERT文

values = [('690-0001', '島根県松江市東朝日町'),
          ('690-0002', '島根県松江市大正町')]
cur = con.cursor()
cur.executemany("insert into ADDRESS values(?, ?)", values)
con.commit()

DELETE文

cur = con.cursor()
cur.execute("delete from ADDRESS")
con.commit()

2006年12月16日

Python用IDE「PyDev」

Python用IDE「PyDev」の紹介。メモ。

2007年09月28日

正式版リリースが迫るPython 3.0

既存のPythonユーザは,3.0に先だってリリースされる予定の2.6を使いながら,徐々に3.x系への移行を進めてゆくことになります。

第4回 正式版リリースが迫るPython 3.0

こういうリリースマネジメントの優秀さが、Pythonの信頼性につながっていると思います。

ビジネスに対して、安心して使える気になりますね。

マイナーバージョンアップだと思ったら後方互換性がなくて、既存のプログラムが動かなくなってしまう、どこかのプログラム言語も見習ってもらいたいと思います。

2008年05月05日

Python用実行ファイル作成ツール

Pythonのスクリプトを単体で動作できるようにする実行ファイル作成ツール。

実行ファイルにすると、Pythonがインストールされていなくても実行できるようになる。
また、実行環境のPythonのバージョンの違いに悩まされることもなくなる。

  • py2exe
    Windows用の実行プログラムを作成できる。

  • PyInstaller
    Windows用とLinux用の実行プログラムを作成できる。

  • bbfreeze
    Windows用とLinux用の実行プログラムを作成できる。

実際に試しながら、それぞれの特徴と違いを確認したい。

2008年06月16日

PyScripterの日本語化

PyScripterオフィシャルのSVN版がついにgettextに対応しました。

いままでは日本語化パッチで日本語化を行っていましたが、次期バージョンからはオフィシャルで日本語対応になりそうです。

今後のPyScripterの日本語化について

Pythonの統合開発環境でおなじみのPyScripterが、次期バージョンからオフィシャルで日本語対応になるそうです。

PyScripterは動作が軽快で、コード補完が便利ですので、ちょっとしたプログラムを作る時に、お世話になっています。

日本語に公式対応することで、一層使いやすくなりますね。
嬉しいニュースです。

2008年07月18日

nkfバージョン2用pythonインターフェース NkfPython がすごく便利

nkfバージョン2用pythonインターフェース NkfPython がすごく便利。
Windows用のバイナリファイルも用意されているので、インストールもコピーするだけ。
とても簡単です。

Python 2.4からCJKCodecsが標準ライブラリに含まれるようになり、日本語が扱いやすくなりました。
ですが、CJKCodecsには文字コードの推測機能がありません。

そこで頼りになるのがnkfです。
nkfもいつの間にかバージョン2になって、utf-8にも対応していました。
ありがたいことです。

使い方も簡単。これからお世話になりそうです。

import nkf

# 文字コードのわからない文字をUTF-8に変換する
some_string = …
output = nkf.nkf('-w', some_string)

# 文字コードを推測する
some_string = …
input_code = nkf.guess(some_string)

追記
WindowsXP python2.6用NKF_pythonのDLLモジュールを作成しました。

2008年07月24日

Google App Engin、Pythonの次の言語はPerl

I'm happy to announce that the Google App Engine team has given me permission to talk about a 20% project inside Google to to add Perl support to App Engine.

Perl on App Engine

Google App Enginで、新たにPerlサポートされるようになりそうです。
Perlの豊富なCPANモジュールがどこまで使うことができるのかが、一つのポイントになりそう。

サポートする言語を増やすよりも、PythonでいいからGoogle App Engineにもっと機能を追加して欲しい。

2008年07月25日

Python用PDFライブラリならReportLab

Python用のPDFライブラリなら「ReportLab」がよさそうです。

簡単な使い方は「Django で PDF を出力する」が参考になります。

そのうち試してみたいと思います。

2008年09月10日

BigTableにおける設計について

「正規化するな、JOIN済みのでっかいテーブルを作れ」とアドバイス(?)していました。

DjangoCon2008 - アクセンスのおまけ -

従来のRDBの常識が通用しませんね。

長い年月をかけて蓄積された多くのノウハウがあるRDBは、安心して使うことができます。
でも、やっぱり適材適所が大事。
RDBですべてをこなそうという考えは危険。

新しいデータベースの考え方も勉強しておいた方がいいかもしれません。

2008年11月06日

多次元のリストのソート

多次元のリストをそのままソートすると、先頭の要素を比較してソートする。
要素がリストではなくタプルでも同じ。

>>> a = [[5, 'x'], [2, 'b'], [3, 'z'], [1, 'd'], [4, 'y']]
>>> a.sort()
>>> a
[[1, 'd'], [2, 'b'], [3, 'z'], [4, 'y'], [5, 'x']]

先頭以外の要素で比較する場合は、cmpキーワードを使用する。
2番目の要素を比較してソートする例。

>>> a = [[5, 'x'], [2, 'b'], [3, 'z'], [1, 'd'], [4, 'y']]
>>> a.sort(cmp = lambda x,y: cmp(x[1], y[1]))
>>> a
[[2, 'b'], [1, 'd'], [5, 'x'], [4, 'y'], [3, 'z']]

マップ型のキーがないときの値の指定方法

マップ型のキーがないときの値の指定方法。

通常、存在しないキーにアクセスするとKeyErrorになります。

>>> a = {}
>>> a['k']
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
KeyError: 'k'

get()を使用すると、キーがないときの値を指定できます。
オブジェクト自身は変更されません。

>>> a = {}
>>> a.get('k', '123')
'123'
>>> a
{}

setdefault()はキーがなければ、キーと値を設定します。
get()と違い、オブジェクトは変更されます。
キーがすでに登録されている場合は、何もしません。

>>> a = {}
>>> a.setdefault('k', 123)
123
>>> a
{'k': 123}
>>> a.setdefault('k', 456)
123
>>> a
{'k': 123}

Python ライブラリリファレンス 3.8 マップ型」を参考にしました。

2008年11月23日

はじめてのPython ネットワークプログラミング

はじめてのPython ネットワークプログラミング』は、Python初心者を対象に、クライアント側のアプリケーションを作成しながら、ネットワークライブラリの使い方を学ぶ本です。

この本の良いところは、実際に使用できるアプリケーションを作成することです。
ライブラリの使い方を示すコードの断片を示すだけではなく、ちゃんと使用できるアプリケーションを作成します。
このことは、初心者が興味を持って学習していく上で、重要なことだと思います。

第1章Pythonのおさらいでは、Pythonの文法をコンパクトにまとめて解説しています。
前著『はじめてのPython』で学んだ読者が復習するのにちょうど良いでしょう。

第2章FTPとTelnetでは、FTPでファイルをアップロードし、Telnetでアップロードしたファイルを操作するソフトウェアを作成します。
いろいろな用途に使用できそうなプログラムなので、これを学んだ読者はいろいろとカスタマイズして楽しむのではないでしょうか。

第3章から第5章では、SQLiteとTkinterを使用したメール送信プログラムを作成します。
GUIアプリケーションは、目に見える形で使用できますから作るのも楽しいと思います。

第6章ではGoogle Newsをメールするスクリプト、第7章では簡易RSSリーダーを作成します。
いずれも興味を持って取り組める題材だと思います。

Amazonのレビューでは、勘違いをして購入した人による不当に低い評価がなされています。
この本が対象としている人にとっては、きっと役に立つ本です。

2008年12月21日

PyScripter 1.9.9.3リリース

PyScripterはPython用の統合開発環境です。
Eclipseよりもずっと軽いのが魅力です。

PyScripter1.9.9.3がリリースされました。

pyscripter - PyScripter Development Site

gettextが組み込まれたため、このバージョンより言語の選択ができるようになりました。

日本語化パッチも必要ありません。いい感じですね。

PyScripter1.9.9.3 - 偏った言語信者の垂れ流し

とのことで、pyscripterのサイトを見てきました。

2009年01月31日

PythonでZIPファイルを作成する

Pythonを使うと簡単にZIPファイルを作成することができました。
標準ライブラリに含まれているので、すぐに使うことができます。

ZIPファイルを作成する方法を簡単にまとめました。

2009年02月02日

PythonのSQLiteライブラリ

SQLite/Rubyのページを更新したついでに、PythonのSQLiteライブラリを調べてみました。

PythonのSQLiteライブラリは、Python 2.5から標準ライブラリに入ったため、
インストール作業が不要で、すぐに使うことができます。

標準ライブラリならバージョンを気にしないですむので、使い勝手が良いですね。

2009年02月14日

RELEASED Python 3.0.1

Python 3.0.1がリリースされました。
バグ修正が行われたようです。

2009年02月23日

WindowsXP python2.6用NKF_pythonのDLLモジュールを作成しました。

WindowsXP python2.6用NKF_pythonのDLLモジュールを作成しました。

nkfバージョン2用 python インターフェースで、公開していただきました。

以下の環境でコンパイルしています。

  • Windows XP
  • Python 2.6.1
  • nkf 2.0.7
  • Microsoft Visual C++ 2008 Express Edition

問題などがあれば、お知らせいただけると喜びます。

今回は最新版であるnkf2.0.9ではなく、nkf2.0.7を使用しています。
というのは、nkf2.0.9ではコンパイルエラーになったためです。
nkf 2.0.9の対応方法をご存じでしたら、教えていただけると助かります。

2009年02月27日

Ubuntu 8.0.4にDjangoの開発環境を作る(1)DjangoのインストールからEclipseとPydevのインストールまで

Ubuntu 8.0.4にDjangoの開発環境を作る手順。
Djangoを使ったアプリケーションをPydevでデバッグできる環境の構築を目指す。

Windowsをお使いの場合は「WindowsにAptana PydevでDjangoの開発環境を構築する」をご覧ください。

Pythonがインストールされているか、確認する。
通常はPythonもインストールされているはず。

$ python --version
Python 2.5.2

UtunbuのDjangoのパッケージはバージョンが古いため、手動でインストールする。

Djangoのホームページからダウンロードする。

ダウンロードしたファイルを展開し、インストールを行う。

$ tar xzvf Django-1.0.2-final.tar.gz
$ cd Django-1.0.2-final
$ sudo python setup.py install

Djangoのインストールが完了したら、動作を確認する。

$ django-admin.py --version
1.0.2 final

バージョン番号が表示されたら、インストールは成功している。

次に、統合開発環境(IDE)をインストールする。

今回は、EclipseとPydevを使用する。

Ubuntuにパッケージが用意されているので、それを使用する。

$ sudo apt-get install eclipse eclipse-pydev

次回「Ubuntu 8.0.4にDjangoの開発環境を作る(2)EclipseとPydevの設定」に続きます。

2009年02月28日

Ubuntu 8.0.4にDjangoの開発環境を作る(2)EclipseとPydevの設定

前回(Ubuntu 8.0.4にDjangoの開発環境を作る(1)DjangoのインストールからEclipseとPydevのインストールまで)の続きです。

Windowsをお使いの場合は「WindowsにAptana PydevでDjangoの開発環境を構築する」をご覧ください。

Djangoを使ったアプリケーションをPydevでデバッグできる環境の構築を目指します。

EclipseとPydevのインストールが完了したら、Eclipseを起動して設定を行います。

メニューから「Window」-「Preferences」を選択します。

「Prefernces」画面が表示されるので、「Pydev」の下にある「interpreter - Python」を選択します。

「Python interpreters」の「New」ボタンを押し「/usr/bin/python」を選択し、登録します。

eclipse-pydev01.png

メニューの「File」-「New」-「Project」を選択します。

「Pydev」の下にある「Pydev Project」を選択します。

eclipse-pydev02.png

「Project name」を入力し(ここでは「MyProject」とします)、「Finish」ボタンを押します。

次のコマンドを端末から入力し、Djangoのプロジェクトを作成します。 ここではプロジェクト名を「manoush」にしています。

$ cd ~/workspace/MyProject/src/
$ django-admin.py startproject manoush

Eclipseに戻り、「Navigator」タブのプロジェクト(MyProject)を右クリックし、「Refresh」を選択します。
これによって、先ほど作成したDjangoプロジェクトのファイルが反映されます。

「Navigator」タブの「MyProject」-「src」-「manoush」-「manage.py」を開きます。

eclipse-pydev03.png

メニューから「Run」-「Debug」を選択します。
「Create, manage, and run configurations」画面が表示されます。

「Python Run」を開き、「New_configuration」を選択します。

「Project」の「Browse」ボタンを押し、プロジェクトを選択します。

「Main Module」の「Browse」ボタンを押し、「manage.py」を選択します。

eclipse-pydev04.png

「Arguments」タブを選択します。

「Program Arguments」に「runserver --noreload」と入力します。

「Apply」ボタンを押し、設定を適用します。

eclipse-pydev05.png

「Debug」ボタンを押し、実行します。

以上で、設定が完了しました。

2009年03月18日

Python Tipsに日付の処理を追加

Python Tipsに「日付の処理いろいろ」を追加しました。

Python ライブラリリファレンス 5.1 datetime -- 基本的な日付型および時間型を見るとわかりますが、
Pythonは日付関連の処理も充実しています。

今回の「日付の処理いろいろ」では、よく使いそうなものを取り上げました。

2009年03月25日

Python で Win32API プログラミング入門

Perl で Win32::API プログラミング入門 を参考にしました。

Python 2.5以降には、ctypes が付属しているので、 今日からすぐに Win32API を利用したプログラミングが出来ます。

# ctypesは、動的リンク/共有ライブラリ内の関数呼び出しを可能にします。
# Linuxなど、Windows以外のOSでも使用することができます。

簡単なメッセージボックスを表示するPythonプログラムは以下になります。

#!C:\Python26\python
# -*- coding: cp932 -*-
import ctypes
ctypes.windll.user32.MessageBoxA(0, 'Hello, World!', 'Message', 0)
# ユニコード版
# ctypes.windll.user32.MessageBoxW(0, u'Hello, World!', u'Message', 0)

このプログラム実行すると、「Hello, World!」と書かれたWindowsメッセージボックスが表示されます。

任意のDLLを扱う場合は、ctypes.windll.LoadLibraryを使用します。

test.dllのソースコード

#include <windows.h>
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
  return 1;
}
__declspec(dllexport) int WINAPI Add(int x, int y)
{
  return x + y;
}

test.dllを扱うPythonスクリプト

#!C:\Python26\python
# -*- coding: cp932 -*-
from ctypes import windll
from ctypes.util import find_library
# dllのパスの取得
path = find_library("test")
# dllの読み込み
dll = windll.LoadLibrary(path)
# dll内の関数の実行
print dll.Add(1, 2) #=> 3

ctypes はとっても便利なモジュールですね。

2009年03月30日

Django×Python

Django×Pythonを読みました。
Djangoについて書かれた希少な本です。

非常にもったいないというか、惜しい本でした。
ターゲットが曖昧なのです。

「Chapter2 Djangoを使いこなすための基礎知識」では、Pythonの入門的な内容になっています。
読者層は、Pythonを使ったことのないまったくの入門者です。

一方、「Chapter4 Djangoをきちんと使う」「Chapter5 Djangoを使いこなす」では、説明が足早に進みます。
読者層は、Djangoに多少触れたことのあるDjangoユーザです。
Python入門者には、難易度が高すぎます。

Appendixの「Djangoチートシート」が100ページ以上もある充実した内容になっています。
本書全体の半分近くを占める分量です。
これほど充実させる必要性を感じません。
Appendixを削り、Chapter4~Cpahter5の内容を充実させ、Python入門者にもわかるレベルにした方が良かったと思います。

うーん、もったいない。

2009年04月08日

WindowsにAptana PydevでDjangoの開発環境を構築する

先日、Ubuntu 8.0.4にDjangoの開発環境を構築する方法を書きました。

やっぱりWindows上でも開発をしたい、ということで、
今回はWindowsにAptana PydevでDjangoの開発環境を構築する方法です。

  1. Aptana Pydevをインストールする

    MergeDoc Project (Eclipse 日本語化)から安定版のバージョンを選択し、Pleiades All in One PythonのFull All in One(JRE あり)をダウンロードします。

    ダウンロードが完了したら、ダウンロードしたファイルを「c:\user」に展開します。
    展開場所のパスの長さに注意してください。
    MAX_PATHを超えていてもエラーメッセージを表示せず、解凍に失敗する解凍ソフトがあるようです。

    C:\
      ├user\
        ├.metadata.default\
        ├eclipse
        ├python
        └xampp
    
  2. Djangoのインストール

    DjangoのサイトからDjangoをダウンロードします。

    ダウンロードしたDjangoのファイル(Django-1.0.2-final.tar.gz)を展開します。
    コマンドプロンプトを起動し、展開したDjangoのフォルダに移動します。
    次のコマンドを実行してインストールします。

    >C:\user\python\python.exe setup.py install
    

    インストールが完了したら、コマンドプロンプトで「C:\user\python\python.exe」と入力して、Pythonインタラクティブシェルを起動します。

    djangoが正しくインストールできたかを確認します。

    >>> import django
    >>> django.VERSION
    (1, 0, 2, 'final', 0)
    
  3. 環境変数の設定

    インストールが終わったら必要に応じて、コマンドプロンプトから「python.exe」や「django-admin.py」のフルパスを入力しないですむように、環境変数の「Path」に「C:\user\python」と「C:\user\python\Scripts」を追加します。

    ;C:\user\python;C:\user\python\Scripts
    

    私はコマンドプロンプトの代わりにnyacusを使用しているので、nyacusの設定ファイル(_nyaファイル)に次の行を追加しました。

    alias python C:\user\python\python.exe
    alias django-admin C:\user\python\python.exe C:\user\python\Scripts\django-admin.py
    

    パスの設定ができると、コマンドプロンプトで入力するときに、フルパスを入力する必要がなくなります。

    >django-admin --version
    1.0.2 final
    

    Eclipse(C:\user\eclipse\eclipse.exe)のショートカットなども作っておくと便利かもしれません。

ここまでは共通の設定です。

これからは、プロジェクトごとの設定になります。

  1. Pydevプロジェクトの設定

    Eclipseを起動します。
    ワークスペースは初期値(../workspace)のまま作成します。

    メニューから「ファイル」-「新規」-「Pydevプロジェクト」を選択します。
    プロジェクト名を入力し(ここでは「MyProject」とします)、「完了」ボタンを押します。

    コマンドプロンプトを起動し、プロジェクトを作成したフォルダに移動します。

    >cd C:\user\workspace\MyProject\src\
    

    Djangoのプロジェクトを作成します。

    >django-admin startproject mysite
    

    プロジェクトが作成されたことを確認します。

    >cd mysite
    >python manage.py runserver
    Validating models...
    0 errors found
     
    Django version 1.0.2 final, using settings 'mysite.settings'
    Development server is running at http://127.0.0.1:8000/
    Quit the server with CTRL-BREAK.
    

    ブラウザでhttp://127.0.0.1:8000/にアクセスします。

    It worked!
    Congratulations on your first Django-powered page.
    

    の画面が表示されると成功です。

    Eclipseに戻り、「Pydevパッケージ・エクスプローラ」タブのプロジェクト(MyProject)を右クリックし、「リフレッシュ」を選択します。
    これによって、先ほど作成したDjangoプロジェクトのファイルが反映されます。

     - MyProject
       - src
         - mysite
           + __init__.py
           + manage.py
           + setting.py
           + urls.py
    
  2. PYTHONPATHの設定

    「プロジェクト・ソース・フォルダー」に先ほど作成した「mysite」を追加します。

    まず、メインメニューから「プロジェクト」-「プロパティー」を選択します。
    「PyDev - PYTHONPATH」を選択し、「ソース・フォルダーの追加」ボタンを押します。
    「MyProject/src/mysite」を選択して、「OK」ボタンを押します。

  3. デバッグの設定

    ブレークポイントの機能を使用できるように設定します。

    manage.pyを選択して、メインメニューから「実行」-「デバッグ」を選択します。
    ※ここでは起動されませんが、問題ありません。

    メインメニューの「実行」-「デバッグの構成」を選択します。
    ※一度「実行」-「デバッグ」を選択すると、「デバッグの構成」が表示されます。

    「引数」タブの「プログラムの引数」に「runserver --noreload」と入力します。
    「適用」ボタンを押し、設定を保存します。

    ブレークポイントが動作するか、確認します。
    manage.pyを開きます。
    3行目(import settingsの行)と11行目(execute_manager(settings)の行)にブレークポイントを追加します。

    manage.pyを選択して、メインメニューの「実行」-「デバッグ」を選択します。
    設定したブレークポイントの行で止まることを確認します。

    プログラムを再開します。

    ブラウザでhttp://127.0.0.1:8000/にアクセスします。

    It worked!
    Congratulations on your first Django-powered page.
    

    の画面が表示されると正しく設定ができています。

     Page not found: /
    

    の画面が表示された場合は、1.の「PyDev - PYTHONPATH」の設定が正しくできていません。
    設定を確認してください。

2009年04月15日

みんなのPython Webアプリ編

みんなのPython Webアプリ編』は、丁寧な説明でしっかりした内容のWebアプリケーションの入門書です。
とても良い入門書で、対象のプログラム言語がJavaやPHPなど初心者プログラマが多いプログラム言語だったら、もっと人気が出たと思います。

本書の対象読者は、Pythonをかじったことがある、CGIプログラミングが初めての人です。
Pythonが初めての人は『みんなのPython』などの入門書で、Pythonを学んでからの方が良いです。

本書が対象としているPythonのバージョンはPython 2.5以上。
現在、主流のバージョンです。

内容についてですが、まず、Webアプリケーションの仕組みをしっかりと説明しているところが良いです。
「CHAPTER 01 Webアプリケーション概論」でWebの仕組み・HTTPの概要を学び、「CHAPTER 05 HTTPの詳細」でHTTPの詳細を、「CHAPTER 13 Webアプリケーションサーバを使った開発」でWebサーバの仕組みを学びます。
このような土台となる部分をちゃんと学ぶことができることは価値があると思います。

作成するサンプルプログラムは、簡単なCGIプログラムから始まり、MVCモデルへと更新します。
そして、テンプレートエンジン、O/Rマッパー、入力フォームを抽象化したウィジェットの作成へと、 本格的なプログラムになっていきます。

サンプルプログラムがRSSリーダーだけでなく、掲示板やメールフォームなど、よく使われるものを取り上げても良かったかなと思います。

CHAPTER 15では、クロスサイトスクリプティングやSQLインジェクションなど、セキュリティについてもしっかり解説されています。

本書では、WebやHTTPについてもちゃんと学べて、MVCモデル・テンプレートエンジン・O/Rマッパーなど本格的なWebアプリケーションの知識を学ぶことができます。
Webアプリケーションの初心者が学ぶには、とても良い本だと思います。

2009年05月12日

propertyを使うにはobjectクラスを継承した新スタイルクラス(new-style class)でなければならない

Pythonのpropertyについて。

objectクラスを継承しない旧スタイルクラス(classic class)でpropertyを使った。

class Foo:
    def __init__(self):
        self.__x = 1
    def getx(self):
        return self.__x
    def setx(self, val):
        self.__x = val
    x = property(getx, setx)

foo = Foo()
print foo.x #=> 1
foo.x = 2
print foo.x #=> 2

一見してうまく動作しているように見える。
ところが、

foo = Foo()
print foo.x #=> 1
print foo.getx() #=> 1
foo.x = 2
print foo.x #=> 2
print foo.getx() #=> 1

と、self.__xは変更されていなかった。

objectクラスを継承した新スタイルクラス(new-style class)にすると、期待通りの動作になる。

class Bar(object):
    def __init__(self):
        self.__x = 1
    def getx(self):
        return self.__x
    def setx(self, val):
        self.__x = val
    x = property(getx, setx)

bar = Bar()
print bar.x #=> 1
print bar.getx() #=> 1
bar.x = 2
print bar.x #=> 2
print bar.getx() #=> 2

propertyを使うには、objectクラスを継承した新スタイルクラス(new-style class)でなければならないようだ。

Python ライブラリリファレンスにも、そのように記載されていました。

property([fget[, fset[, fdel[, doc]]]])
新しい形式のクラス (object から導出されたクラス) におけるプロパティ属性を返します。

Python ライブラリリファレンス 2.1 組み込み関数

2009年05月14日

幅優先探索

Javaによる知能プログラミング入門』の「2.探索とパターン照合」にある幅優先探索のソースコードをPythonで実装してみました。

有向グラフとして表現されている状態空間の、初期状態から目標状態までの探索を行います。

状態空間

元のJavaのコードはSearchクラスのbreadthFirstメソッドとして実装されていますが、 今回は関数として実装しました。

実際に探索を行うのはbreadth_first()関数です。
ポイントは隣接する状態を探索して、探索予定ノードリスト(変数open)に追加するところです。

for m in node.children:
    if m in open or m in closed:
        continue
    m.pointer = node
    if m == goal:
        open.insert(0, m)
    else:
        open.append(m)

探索予定ノードリスト(変数open)の末尾に隣接する状態を追加しているので、幅優先探索になります。
ここを変えると深さ優先探索になります。

#! /usr/bin/python
# -*- coding: Shift_JIS -*-

class Node:
    def __init__(self, name):
        """
        @param name: 都市名
        """
        self.name = name
        self.children = [] #遷移できるノードのリスト
        self.pointer = None #解表示のためのポインタ

    def __str__(self):
        return self.name

def nodes_str(nodes):
    """
    Nodeのリストの出力用文字列を作成する
    @param nodes: Nodeのリスト
    """
    return map(str, nodes)

def make_state_space():
    """
    状態空間の生成
    @return: ノードのリストを返す。
    """
    node = [Node("L.A.Airport"),
            Node("UCLA"),
            Node("Hoolywood"),
            Node("Anaheim"),
            Node("GrandCanyon"),
            Node("SanDiego"),
            Node("Downtown"),
            Node("Pasadena"),
            Node("DisneyLand"),
            Node("Las Vegas")]
    node[0].children = [node[1], node[2]]
    node[1].children = [node[2], node[6]]
    node[2].children = [node[3], node[6], node[7]]
    node[3].children = [node[4], node[7], node[8]]
    node[4].children = [node[8], node[9]]
    node[5].children = [node[1]]
    node[6].children = [node[5], node[7]]
    node[7].children = [node[8], node[9]]
    node[8].children = [node[9]]
    return node

def print_solution(node):
    """
    解の表示
    """
    if node.pointer == None:
        print node
    else:
        print node, "<-",
        print_solution(node.pointer)

def breadth_first(start, goal):
    """
    幅優先探索
    @param start: 探索開始ノード
    @param goal: 探索終了ノード
    """
    open = [start] #探索予定のノードのリスト
    closed = [] #探索を終了したノードのリスト
    success = False
    step = 0

    while 1:
        step += 1
        print "STEP:", step
        print "OPEN:", nodes_str(open)
        print "closed:", nodes_str(closed)

        if len(open) == 0:
            success = False
            break

        node = open.pop(0)
        if node == goal:
            success = True
            break

        closed.append(node)
        for m in node.children:
            if m in open or m in closed:
                continue
            m.pointer = node
            if m == goal:
                open.insert(0, m)
            else:
                open.append(m)
    if success:
        print "*** Solution ***"
        print_solution(goal)

if __name__ == "__main__":
    nodes = make_state_space()
    breadth_first(nodes[0], nodes[-1])

ちなみに、NetBeansのPythonプラグインを使ってみました。
よくできていて、なかなか快適です。

2009年05月15日

深さ優先探索

前回の「幅優先探索」の続きです。

Javaによる知能プログラミング入門』の「2.探索とパターン照合」にある深さ優先探索のソースコードをPythonで実装してみました。

有向グラフとして表現されている状態空間の、初期状態から目標状態までの探索を行います。

状態空間

元のJavaのコードはSearchクラスのbreadthFirstメソッドとして実装されていますが、 今回は関数として実装しました。

実際に探索を行うのはdepth_first()関数です。
ポイントは隣接する状態を探索して、探索予定ノードリスト(変数open)に追加するところです。

j = 0
for m in node.children:
    if m in open or m in closed:
        continue
    m.pointer = node
    if m == goal:
        open.insert(0, m)
    else:
        open.insert(j, m)
    j += 1

探索予定ノードリスト(変数open)の先頭から隣接する状態を追加しているので、深さ優先探索になります。
ここを変えると幅優先探索になります。

#! /usr/bin/python
# -*- coding: Shift_JIS -*-

class Node:
    def __init__(self, name):
        """
        @param name: 都市名
        """
        self.name = name
        self.children = [] #遷移できるノードのリスト
        self.pointer = None #解表示のためのポインタ

    def __str__(self):
        return self.name

def nodes_str(nodes):
    """
    Nodeのリストの出力用文字列を作成する
    @param nodes: Nodeのリスト
    """
    return map(str, nodes)

def make_state_space():
    """
    状態空間の生成
    @return: ノードのリストを返す。
    """
    node = [Node("L.A.Airport"),
            Node("UCLA"),
            Node("Hoolywood"),
            Node("Anaheim"),
            Node("GrandCanyon"),
            Node("SanDiego"),
            Node("Downtown"),
            Node("Pasadena"),
            Node("DisneyLand"),
            Node("Las Vegas")]
    node[0].children = [node[1], node[2]]
    node[1].children = [node[2], node[6]]
    node[2].children = [node[3], node[6], node[7]]
    node[3].children = [node[4], node[7], node[8]]
    node[4].children = [node[8], node[9]]
    node[5].children = [node[1]]
    node[6].children = [node[5], node[7]]
    node[7].children = [node[8], node[9]]
    node[8].children = [node[9]]
    return node

def print_solution(node):
    """
    解の表示
    """
    if node.pointer == None:
        print node
    else:
        print node, "<-",
        print_solution(node.pointer)

def depth_first(start, goal):
    """
    深さ優先探索
    @param start: 探索開始ノード
    @param goal: 探索終了ノード
    """
    open = [start] #探索予定のノードのリスト
    closed = [] #探索を終了したノードのリスト
    success = False
    step = 0

    while 1:
        step += 1
        print "STEP:", step
        print "OPEN:", nodes_str(open)
        print "closed:", nodes_str(closed)

        if len(open) == 0:
            success = False
            break

        node = open.pop(0)
        if node == goal:
            success = True
            break

        closed.append(node)
        j = 0
        for m in node.children:
            if m in open or m in closed:
                continue
            m.pointer = node
            if m == goal:
                open.insert(0, m)
            else:
                open.insert(j, m)
            j += 1
    if success:
        print "*** Solution ***"
        print_solution(goal)

if __name__ == "__main__":
    nodes = make_state_space()
    depth_first(nodes[0], nodes[-1])

2009年05月16日

分岐限定法

前回の「深さ優先探索」の続きです。

Javaによる知能プログラミング入門』の「2.探索とパターン照合」にある分岐限定法のソースコードをPythonで実装してみました。

有向グラフとして表現されている状態空間の、初期状態から目標状態までの探索を行います。

ノード間の□の中の数字は、各ノード間のコストを表します。
分岐限定法では、コストが最も小さいノードからたどっていきます。

ポイントはソースコードの次の部分です。 ノードのg_valueは、初期状態からそのノードへの最小コストを表します。

# node を展開して子節点をすべて求める
for m in node.children:
    # 子節点mがopenにもclosedにも含まれていなければ
    if m not in open and m not in closed:
        # m から node へのポインタを付ける.
        m.pointer = node
        # nodeまでの評価値とnode->mのコストを足したものをmの評価値とする
        m.g_value = node.g_value + node.get_cost(m)
        open.append(m)
    # 子節点mがopenに含まれているならば,
    if m in open:
        gmn = node.g_value + node.get_cost(m)
        if gmn < m.g_value:
            m.g_value = gmn
            m.pointer = node
# Nodeをg_valueの昇順(小さい順)に列べ換える
sort_upper_by_g_value(open)

探索するノードが見つかると、g_valueを計算します。
そして、g_valueでソートしてコストの小さいものから探索します。

#! /usr/bin/python
# -*- coding: Shift_JIS -*-

def printNodes(nodes):
    """
    Nodeのリストの出力用文字列を作成する
    nodes Nodeのリスト
    """
    return map(str, nodes)

class Node(object):
    def __init__(self, name):
        self.name = name
        self.children = [] #遷移できるノードのリスト
        self.children_costs = {} #<Node, Integer>
        self.pointer = None #解表示のためのポインタ
        self.__g_value = 0 # コスト
        self.has_g_value = False

    def get_g_value(self):
        return self.__g_value
    def set_g_value(self, value):
        self.has_g_value = True
        self.__g_value = value
    g_value = property(get_g_value, set_g_value)

    def add_child(self, child, cost):
        """
        @param child: この節点の子節点
        @param cost:  その子節点までのコスト
        """
        self.children.append(child)
        self.children_costs[child] = cost

    def get_cost(self, child):
        """
        子節点までのコストを取得する
        @param child: この節点の子節点
        @return: 子節点までのコスト
        """
        return self.children_costs[child]

    def __str__(self):
        result = self.name
        if self.has_g_value:
            result = "%s(g:%d)" % (result, self.__g_value)
        return result

def nodes_str(nodes):
    """
    Nodeのリストの出力用文字列を作成する
    @param nodes: Nodeのリスト
    """
    return map(str, nodes)

def make_state_space():
    """
    状態空間の生成
    @return: ノードのリストを返す。
    """
    node = [Node("L.A.Airport"),
            Node("UCLA"),
            Node("Hoolywood"),
            Node("Anaheim"),
            Node("GrandCanyon"),
            Node("SanDiego"),
            Node("Downtown"),
            Node("Pasadena"),
            Node("DisneyLand"),
            Node("Las Vegas")]
    node[0].add_child(node[1],1)
    node[0].add_child(node[2],3)
    node[1].add_child(node[2],1)
    node[1].add_child(node[6],6)
    node[2].add_child(node[3],6)
    node[2].add_child(node[6],6)
    node[2].add_child(node[7],3)
    node[3].add_child(node[4],5)
    node[3].add_child(node[7],2)
    node[3].add_child(node[8],4)
    node[4].add_child(node[8],2)
    node[4].add_child(node[9],1)
    node[5].add_child(node[1],1)
    node[6].add_child(node[5],7)
    node[6].add_child(node[7],2)
    node[7].add_child(node[8],3)
    node[7].add_child(node[9],7)
    node[8].add_child(node[9],5)
    return node

def print_solution(node):
    """
    解の表示
    """
    if node.pointer == None:
        print node
    else:
        print node, "<-",
        print_solution(node.pointer)

def sort_upper_by_g_value(open):
    """
    Nodeをg_valueの昇順(小さい順)に列べ換える
    @param open: Nodeのリスト
    """
    def g_value_compare(x, y):
        return x.g_value - y.g_value
    open.sort(g_value_compare)

def branch_and_bound(start, goal):
    """
    分岐限定法
    @param start: 探索開始ノード
    @param goal: 探索終了ノード
    """
    open = [start] #探索予定のノードのリスト
    start.g_value = 0
    closed = [] #探索を終了したノードのリスト
    success = False
    step = 0

    while 1:
        step += 1
        print "STEP:", step
        print "OPEN:", nodes_str(open)
        print "closed:", nodes_str(closed)

        if len(open) == 0:
            success = False
            break

        node = open.pop(0)
        if node == goal:
            success = True
            break

        closed.append(node)
        # node を展開して子節点をすべて求める.
        for m in node.children:
            # 子節点mがopenにもclosedにも含まれていなければ,
            if m not in open and m not in closed:
                # m から node へのポインタを付ける.
                m.pointer = node
                # nodeまでの評価値とnode->mのコストを足したものをmの評価値とする
                m.g_value = node.g_value + node.get_cost(m)
                open.append(m)
            # 子節点mがopenに含まれているならば,
            if m in open:
                gmn = node.g_value + node.get_cost(m)
                if gmn < m.g_value:
                    m.g_value = gmn
                    m.pointer = node
        # Nodeをg_valueの昇順(小さい順)に列べ換える
        sort_upper_by_g_value(open)
    if success:
        print "*** Solution ***"
        print_solution(goal)

if __name__ == "__main__":
    nodes = make_state_space()
    branch_and_bound(nodes[0], nodes[-1])

2009年05月18日

A*アルゴリズム

前回の「分岐限定法」の続きです。

Javaによる知能プログラミング入門』の「2.探索とパターン照合」にあるA*アルゴリズムのソースコードをPythonで実装してみました。
本では分岐限定法の後に山登り法と最良優先探索を説明して問題点を明らかにし、その後でA*アルゴリズムが説明されています。

有向グラフとして表現されている状態空間の、初期状態から目標状態までの探索を行います。

ノード間の□の中の数字は、各ノード間のコストを表します。
各ノートに添付された○の中の数字は、そのノードのヒューリスティックな値を表します。

#! /usr/bin/python
# -*- coding: Shift_JIS -*-

def printNodes(nodes):
    """
    Nodeのリストの出力用文字列を作成する
    nodes Nodeのリスト
    """
    return map(str, nodes)

class Node(object):
    def __init__(self, name, value):
        self.name = name
        self.children = [] #遷移できるノードのリスト
        self.children_costs = {} #<Node, Integer>
        self.pointer = None #解表示のためのポインタ
        self.__g_value = 0 # コスト
        self.__f_value = 0 # 評価値
        self.has_g_value = False
        self.has_f_value = False
        self.h_value = value # ヒューリスティック値

    def get_f_value(self):
        return self.__f_value
    def set_f_value(self, value):
        self.has_f_value = True
        self.__f_value = value
    f_value = property(get_f_value, set_f_value)

    def get_g_value(self):
        return self.__g_value
    def set_g_value(self, value):
        self.has_g_value = True
        self.__g_value = value
    g_value = property(get_g_value, set_g_value)

    def add_child(self, child, cost):
        """
        @param child: この節点の子節点
        @param cost:  その子節点までのコスト
        """
        self.children.append(child)
        self.children_costs[child] = cost

    def get_cost(self, child):
        """
        子節点までのコストを取得する
        @param child: この節点の子節点
        @return: 子節点までのコスト
        """
        return self.children_costs[child]

    def __str__(self):
        result = "%s(h:%d)" % (self.name, self.h_value)
        if self.has_g_value:
            result = "%s(g:%d)" % (result, self.g_value)
        if self.has_f_value:
            result = "%s(f:%d)" % (result, self.f_value)
        return result

def nodes_str(nodes):
    """
    Nodeのリストの出力用文字列を作成する
    @param nodes: Nodeのリスト
    """
    return map(str, nodes)

def make_state_space():
    """
    状態空間の生成
    @return: ノードのリストを返す。
    """
    node = [Node("L.A.Airport",0),
            Node("UCLA",7),
            Node("Hoolywood",4),
            Node("Anaheim",6),
            Node("GrandCanyon",1),
            Node("SanDiego",2),
            Node("Downtown",3),
            Node("Pasadena",4),
            Node("DisneyLand",2),
            Node("Las Vegas",0)]
    node[0].add_child(node[1],1)
    node[0].add_child(node[2],3)
    node[1].add_child(node[2],1)
    node[1].add_child(node[6],6)
    node[2].add_child(node[3],6)
    node[2].add_child(node[6],6)
    node[2].add_child(node[7],3)
    node[3].add_child(node[4],5)
    node[3].add_child(node[7],2)
    node[3].add_child(node[8],4)
    node[4].add_child(node[8],2)
    node[4].add_child(node[9],1)
    node[5].add_child(node[1],1)
    node[6].add_child(node[5],7)
    node[6].add_child(node[7],2)
    node[7].add_child(node[8],3)
    node[7].add_child(node[9],7)
    node[8].add_child(node[9],5)
    return node

def print_solution(node):
    """
    解の表示
    """
    if node.pointer == None:
        print node
    else:
        print node, "<-",
        print_solution(node.pointer)

def sort_upper_byf_value(open):
    """
    Nodeをf_valueの昇順(小さい順)に列べ換える
    @param open: Nodeのリスト
    """
    def f_value_compare(x, y):
        return x.f_value - y.f_value
    open.sort(f_value_compare)

def a_star(start, goal):
    """
    最良優先探索
    @param start: 探索開始ノード
    @param goal: 探索終了ノード
    """
    open = [start] #探索予定のノードのリスト
    start.g_value = 0
    start.f_value = 0
    closed = [] #探索を終了したノードのリスト
    success = False
    step = 0

    while 1:
        step += 1
        print "STEP:", step
        print "OPEN:", nodes_str(open)
        print "closed:", nodes_str(closed)

        if len(open) == 0:
            success = False
            break

        node = open.pop(0)
        if node == goal:
            success = True
            break

        closed.append(node)
        for m in node.children:
            gmn = node.g_value + node.get_cost(m)

            if m not in open and m not in closed:
                m.g_value = gmn

            if m in open:
                if gmn < m.g_value:
                    m.g_value = gmn
                    m.pointer = node

            fmn = gmn + m.h_value
            if m not in open and m not in closed:
                m.pointer = node
                m.f_value = fmn
                open.append(m)

            if m in open and fmn < m.f_value:
                m.f_value = fmn
                open.append(m)
                m.pointer = node

            if m in closed and fmn < m.f_value:
                m.pointer = node
                m.f_value = fmn
                closed.remove(m)
                open.append(m)

        sort_upper_byf_value(open)

    if success:
        print "*** Solution ***"
        print_solution(goal)

if __name__ == "__main__":
    nodes = make_state_space()
    a_star(nodes[0], nodes[-1])

2009年05月19日

パターン照合(1)

Javaによる知能プログラミング入門』の「2.探索とパターン照合」にあるパターン照合プログラムのソースコードをPythonで実装してみました。

このプログラムはパターンが文字列に一致するかどうかをテストします。
パターンでは、「?」を先頭に付加した文字列を変数とします。
たとえば「?x」は変数です。

次のような動作を期待します。

文字の比較

matching("Hanako", "Hanako") #=> True
matching("Taro", "Hanako") #=> False

変数を含むパターンとの比較

matching("I am ?x", "I am Hanako") #=> True(?x : Hanako)

同じ変数を複数回使用できる。

matching("?x is ?x", "a is a") #=> True(?x : a)
matching("?x is ?x", "a is b") #=> False

複数の変数を使用できる

matching("?x is ?y", "a is b") #=> True(?x : a, ?y : b)

ソースコードの全体です。

#! /usr/bin/python
# -*- coding: Shift_JIS -*-

import re

def matching(string1, string2):
    """
    実際にマッチングを行う関数
    @param string1: マッチングをする文字列
    @param string2: マッチングをする文字列
    @return: 成功ならTrue,失敗なら False
    """
    vars = {} #変数と値の辞書

    print string1
    print string2

    # 同じなら成功
    if string1 == string2: return True

    # 各々トークンに分ける
    r = re.compile('\s')
    sl1 = r.split(string1)
    sl2 = r.split(string2)

    # 数が異なったら失敗
    if len(sl1) != len(sl2): return False

    # 定数同士
    for s1, s2 in zip(sl1, sl2):
        if not token_matching(s1, s2, vars):
            return False

    # 最後まで O.K. なら成功
    print vars
    return True

def token_matching(token1, token2, vars):
    if token1 == token2: return True
    if var(token1) and not var(token2): return var_matching(token1, token2, vars)
    if not var(token1) and var(token2): return var_matching(token2, token1, vars)
    return False

def var(str):
    """ strは変数か。先頭が ? なら変数。 """
    return str.startswith("?")

def var_matching(vartoken, token, vars):
    if vars.has_key(vartoken):
        if vars[vartoken] == token:
            return True
        else:
            return False
    vars[vartoken] = token
    return True

if __name__ == "__main__":
    print matching("Hanako", "Hanako")
    print matching("Taro", "Hanako")
    print matching("I am ?x", "I am Hanako")
    print matching("?x is ?x", "a is a")
    print matching("?x is ?x", "a is b")
    print matching("?x is ?y", "a is b")

2009年05月20日

ユニフィケーション照合アルゴリズム

前回(パターン照合(1))の続き。

Javaによる知能プログラミング入門』の「2.探索とパターン照合」にあるパターン照合プログラムのソースコードをPythonで実装してみました。

前回のパターン照合プログラムは文字列とパターンが一致するかをテストしました。
今回のプログラムでは、2つのパターンが矛盾のない変数代入によって同一と判断できるかをテストします。

次のパターンをテストします。

print Unify().unify("Takayuki", "Takayuki")
print Unify().unify("Takayuki", "Takoyuki")
print Unify().unify("?x am Takayuki", "I am Takayuki")
print Unify().unify("?x is ?x", "a is b")
print Unify().unify("?x is ?x", "a is a")
print Unify().unify("?x is a", "b is ?y")
print Unify().unify("?x is a", "?y is ?x")

ユニフィケーション照合アルゴリズムというらしい。

関数をまたかってやりとりする変数(vars,buffer1,buffer2)があるので、クラスにしました。
読みやすくなったかどうかは、微妙なところです。

#! /usr/bin/python
# -*- coding: Shift_JIS -*-
import re

class Unify(object):
    def __init__(self):
        self.vars = {} #変数と値の辞書

    def unify(self, str1, str2):
        print str1
        print str2

        # 同じなら成功
        if str1 == str2: return True

        # 各々トークンに分ける
        r = re.compile('\s')
        self.buffer1 = r.split(str1)
        self.buffer2 = r.split(str2)

        # 数が異なったら失敗
        if len(self.buffer1) != len(self.buffer2): return False

        for i in range(len(self.buffer1)):
            if not self.token_matching(self.buffer1[i], self.buffer2[i]):
                return False

        print self.vars
        return True

    def token_matching(self, token1, token2):
        if token1 == token2: return True
        if var(token1) and not var(token2): return self.var_matching(token1, token2)
        if not var(token1) and var(token2): return self.var_matching(token2, token1)
        if var(token1) and var(token2): return self.var_matching(token1, token2)
        return False

    def var_matching(self, vartoken, token):
        if self.vars.has_key(vartoken):
            if token == self.vars[vartoken]:
                return True
            else:
                return False
        else:
            self.replace_buffer(vartoken, token);
            if self.vars.has_key(vartoken):
                self.replace_bindings(vartoken,token)
            self.vars[vartoken] = token
        return True

    def replace_buffer(self, pre_string, post_string):
        def replace_pre(x):
            if pre_string == x:
                return post_string
            else:
                return x
        self.buffer1 = map(replace_pre, self.buffer1)
        self.buffer2 = map(replace_pre, self.buffer2)

    def replace_bindings(self, pre_string, post_string):
        for key in self.vars.keys():
            if pre_string == self.vars[key]:
                self.vars[key] = post_string

def var(str):
    """ strは変数か。先頭が ? なら変数。 """
    return str.startswith("?")

if __name__ == "__main__":
    print Unify().unify("Takayuki", "Takayuki")
    print Unify().unify("Takayuki", "Takoyuki")
    print Unify().unify("?x am Takayuki", "I am Takayuki")
    print Unify().unify("?x is ?x", "a is b")
    print Unify().unify("?x is ?x", "a is a")
    print Unify().unify("?x is a", "b is ?y")
    print Unify().unify("?x is a", "?y is ?x")

2009年05月24日

Django TIPSのページを作成しました。

Django TIPSのページを作成しました。

勉強したことを少しずつ記事として掲載していきたいと思います。

2009年07月13日

Monostateパターン

もし全部のメソッドをクラスメソッドにしてしまえば、インスタンス間の区別がなくなります。つまり、インスタンスが1個しかないのと同じです。

Singletonパターン (2) - ぜ~んぶクラスメソッド

それはSingletonパターンではなくて、Monostateパターンですね。

Monostateパターンは『アジャイルソフトウェア開発の奥義』を読んで知りました。

オブジェクト指向における再利用のためのデザインパターン』に掲載されているGoFによる23のデザインパターン以外にも、デザインパターンはたくさんあります。

デザインパターン紹介のページがよくまとまっていて、勉強になります。

2009年07月29日

Django 1.1 released

Django 1.1がリリースされた模様。

Django 1.0系のコードはDjango 1.1でもそのまま動くはずですが、変更点には目を通しておいた方がいいかもしれません。

ダウンロードはダウンロードのページからどうぞ。

2009年08月07日

プログラム言語における見た目と意味の不一致

BEST SOFTWARE WRITING』を読んで、なるほど、と思った。

C系の言語(C、C++、Java)では、人の目はインデントをブロックkの定義としてみるが、コンパイラの方は{}を見る。
だからインデントと括弧が対応していない場合、人の目にはよりわかりにくいほう──{}──が勝つことになる。
(中略)
なぜ1つの方法にこだわって、コードの見た目と意味が一致するようにしないのか?

BEST SOFTWARE WRITING

インデントのずれによるソースコードの見た目とコンパイラが解約する意味の不一致が、 バグを生み出すことは珍しくありません。

# よくある間違い
if (x > 10)
    y = 0;
    z = 0;

コーディング規約を定めることで、このようなバグを減らそうとする試みが一般的です。

# コーディング規約で{}を強制
if (x > 10) {
    y = 0;
    z = 0;
}

Pythonはインデントを文法に組み入れることによって、見た目と意味を一致させて、効率的なプログラミングを実現しました。
プログラム言語に「ソースコードの見た目」という情報を取り入れたという点で画期的だったのかもしれません。

それから、

何らかのコーディングスタイルが、一般的なスタイルと比べて非常に大きな利点を持つことは、 これまでのところなかったし、これからもないだろう。

BEST SOFTWARE WRITING

というのも、その通り。
ハンガリアン記法という効率の悪いコーディング規約もあるけど。

About Python

ブログ「山本隆の開発日誌」のカテゴリ「Python」に投稿されたすべてのエントリーのアーカイブのページです。過去のものから新しいものへ順番に並んでいます。

前のカテゴリはPerlです。

次のカテゴリはRubyです。

他にも多くのエントリーがあります。メインページアーカイブページも見てください。

Powered by
Movable Type 3.35