search this site:

Chaotic Neutral

左にも右にもよらず、自由な生き方探し。

Python ― 続Hello, world!

Hello, world!には「print 'Hello, world!'」以外にもやり方がある。

def main():
	s = 'Hello, world!'
	print s
main()

def main():で関数を宣言し、その後の2行で関数を定義する。第4行のmain()で関数を呼び出し、「Hello, world!」を表示させる。この例では特に利点があるようには思えないが、main()からプログラムの実行を始めたいという人もいるかもしれない。

次の例、

class HW:
	def main(self):
		self.s = 'Hello, world!'
		print self.s
		import pickle
		print pickle.dumps(self)

p= HW()
p.main()
を実行すると、以下のような結果になる。
Hello, world!
(i__main__
HW
p0
(dp1
S's'
p2
S'Hello, world!'
p3
sb.

この例では、HWというクラスを作成し、クラスのインスタンスpのmain(self)をp.main()で呼び出すことで、'Hello, world!'を表示させている。「(i__main__」から「sb.」までの数行は、インスタンスpの状態をpickle.dumps(self)で文字列として表現したものだ。

プログラム本体をクラスとして設計すると、実行中の状態を丸ごと文字列にして、必要であればテキストファイルなどに保存できる。

Python ― Hello, world!

もちろん、Pythonの入門者 ― というより、プログラミングの入門者かもしれない ― として、私も各種入門書の不親切さに頭を悩ませる1人であるので、PythonでのHello, world!経験にここでこだわってみたい。

コマンドプロンプトを起動して、「python」と打ちこむと、「python.exe」が入っているフォルダがpath環境変数に設定されていれば、コマンドプロンプト画面に「>>>」が現われて、ユーザーからのpython構文入力を受け付ける。pythonから抜けるには、「exit()」を使う。

コマンドプロンプトでの「python」でpython.exeが起動しなければ、path環境変数にpython.exeを登録しなくちゃいけない。コマンドプロンプトでは、「path <python.exeの入っているフォルダ>;%path%」で一時登録できる。私はD:\Python25にpython.exeを置いているので、

C:\>path D:\Python25;%path%
で一時登録した。

次に、IDLEでも何でもいいけど、エディタを起動する。IDLEを使う場合には、FileメニューからNew Windowを選択すると、新しいファイルを編集するための窓が現れるので、そこに次の1行

print 'Hello, world!'
を記述して、「HelloWorld.py」あたりの適当な名前でどこかに保存する。私はH:\に保存した。

後は、次のような手順でHelloWorld.pyを実行する。

C:\>cd /d H:\
H:\>python HelloWorld.py
Hello, world!

とりあえず一件落着といいたいところだけど、「これをどうやってPythonをインストールしていない環境で実行するの?」という疑問が頭から離れない。

調べると、py2exeというのがあったので、Python 2.5用のpy2exeを入手して、インストールした。

ここでしばらく試行錯誤して、

from distutils.core import setup
import py2exe
setup(console=['HelloWorld.py'])
という内容のファイルを作り、「hws.py」という名前で保存し、コマンドプロンプトから、「python hws.py py2exe」と打ちこんでやると、長いメッセージ
H:\>python hws.py py2exe
running py2exe
creating H:\build
creating H:\build\bdist.win32
creating H:\build\bdist.win32\winexe
creating H:\build\bdist.win32\winexe\collect-2.5
creating H:\build\bdist.win32\winexe\bundle-2.5
creating H:\build\bdist.win32\winexe\temp
creating H:\dist
*** searching for required modules ***
*** parsing results ***
creating python loader for extension 'unicodedata'
creating python loader for extension 'bz2'
*** finding dlls needed ***
*** create binaries ***
*** byte compile python files ***
byte-compiling D:\Python25\lib\StringIO.py to StringIO.pyc
byte-compiling D:\Python25\lib\UserDict.py to UserDict.pyc
byte-compiling D:\Python25\lib\atexit.py to atexit.pyc
中略
byte-compiling D:\Python25\lib\warnings.py to warnings.pyc
byte-compiling H:\build\bdist.win32\winexe\temp\bz2.py to bz2.pyc
byte-compiling H:\build\bdist.win32\winexe\temp\unicodedata.py to unicodedata.pyc
*** copy extensions ***
copying D:\Python25\DLLs\bz2.pyd -> H:\dist
copying D:\Python25\DLLs\unicodedata.pyd -> H:\dist
*** copy dlls ***
copying D:\Python25\python25.dll -> H:\dist
setting sys.winver for 'H:\dist\python25.dll' to 'py2exe'
copying D:\Python25\w9xpopen.exe -> H:\dist
copying D:\Python25\MSVCR71.dll -> H:\dist
copying D:\Python25\lib\site-packages\py2exe\run.exe -> H:\dist\HelloWorld.exe

*** binary dependencies ***
Your executable(s) also depend on these dlls which are not included,
you may or may not need to distribute them.

Make sure you have the license if you distribute any of them, and
make sure you don't distribute files belonging to the operating system.

   ADVAPI32.dll - C:\WINDOWS\system32\ADVAPI32.dll
   USER32.dll - C:\WINDOWS\system32\USER32.dll
   SHELL32.dll - C:\WINDOWS\system32\SHELL32.dll
   KERNEL32.dll - C:\WINDOWS\system32\KERNEL32.dll
が現われて、コンパイルが終了し、HelloWorld.exeが作られていて、実行に必要なライブラリと一緒にH:\distに入っているはず。
H:\>cd dist
H:\dist>dir
 ドライブ H のボリューム ラベルがありません。
 ボリューム シリアル番号は 40A6-9A89 です

 H:\dist のディレクトリ

2008/01/07  13:05    <DIR>          .
2008/01/07  13:05    <DIR>          ..
2007/04/18  08:51            77,824 bz2.pyd
2008/01/07  13:05            15,872 HelloWorld.exe
2008/01/07  13:05           710,503 library.zip
2006/07/11  18:35           348,160 MSVCR71.dll
2007/04/18  08:51         2,113,536 python25.dll
2007/04/18  08:51           475,136 unicodedata.pyd
2007/04/18  08:51             4,608 w9xpopen.exe
               7 個のファイル           3,745,639 バイト
               2 個のディレクトリ  146,065,920,000 バイトの空き領域
H:\dist>HelloWorld.exe
Hello, world!

これでようやく一件落着。

Python ― みくるの大小

>>> class Chara:
	def __init__(self,s):
		self.name = s

#とりあえず、前回と同じクラスを使う。

>>> cl = [Chara('Haruhi')]
>>> cl += [Chara('Mikuru')] #cl = cl + [Chara('Mikuru')]でもいい。
>>> cl
[<__main__.Chara instance at 0x00DB9D78>, <__main__.Chara instance at 0x00DB9DC8>]

#いうまでもなく、cl[0]とcl[1]は別のインスタンスなので、別々のアドレスに格納されている。とりあえず、年齢でも設定しておこう。

>>> cl[1].age = 17

#さて、もう1つself.name='Mikuru'なインスタンスが欲しい。

>>> cl += cl[1]

Traceback (most recent call last):
  File "", line 1, in 
    cl += cl[1]
TypeError: iteration over non-sequence

#↑初歩的な間違い。

>>> cl += [cl[1]]
>>> cl
[<__main__.Chara instance at 0x00DB9D78>,
<__main__.Chara instance at 0x00DB9DC8>,
<__main__.Chara instance at 0x00DB9DC8>]

#読みやすくするために、折り返しを入れた。#clにcl[1]をもう1つ加えたが、cl[1]とcl[2]は同じアドレスに入っている。

>>> cl[2].age = '(Confidential)'
>>> cl[1].age
'(Confidential)'

#当然だが、cl[2].ageを「(Confidential)」にしたため、cl[1].ageもそうなってしまった。

#(俺たちに必要なのは、全く同一の2人の みくる じゃない。みくるとそのコピーなのだ。)

>>> cl[1].age = 17 #cl[1]のageを元に戻した。
>>> import copy #copyモジュールをインポートする。
>>> cl[2] = copy.copy(cl[1]) #cl[2]にcl[1]のコピーを入れる。
>>> cl
[<__main__.Chara instance at 0x00DB9D78>,
<__main__.Chara instance at 0x00DB9DC8>,
<__main__.Chara instance at 0x00DC3C60>]

#今度はcl[1]とcl[2]のアドレスが違うものになっている。

#これで、cl[2].ageを書き換えても、cl[1].ageは変わらないはず。

>>> cl[2].age = '(Confidential)'
>>> cl[1].age
17

Python ― リスト上の彼女ら

#Pythonのシェルで遊んでみた。

#とりあえず、クラスを作ってみる。

>>> class Chara:
	def __init__(self, s):
		self.name = s

#「class」はクラスを定義するキーワード、「Chara」がクラス名、「__init__(self,s)」はコンストラクタで、「self」がないとエラーになる。sはインスタンス作成時にPythonに渡すものを入れる仮引数。self.nameはCharaクラスのプロパティ。

>>> p=Chara('Haruhi')
>>> p.name
'Haruhi'

#「Chara('Haruhi')」で作ったインスタンスを変数pに格納し、「p.name」でnameプロパティを求めると、'Haruhi'を返してくれる。

#あ、性別も設定したくなった。

>>> p.sex='female'
>>> p.sex
'female'

#Charaクラスにはsexプロパティが設定されていないにもかかわらず、pはsexプロパティを持つことができる。このあたりのいい加減さに少々カルチャーショックを覚える。

#ところで、このpそのものなんだが……

>>> p
<__main__.Chara instance at 0x00DB9D00>

#pの正体を問い合わせると、メモリ上でpを格納しているアドレスが帰ってくる。

#とりあえず、このpをリストに入れてみる。

>>> cl[0] = p

Traceback (most recent call last):
  File "", line 1, in 
    cl[0] = p
NameError: name 'cl' is not defined

#エラー発生。実は、Pythonでリストに項目を追加する表現は一風変わっている。

>>> cl = [p]
>>> cl[0]
<__main__.Chara instance at 0x00DB9D00>

#cl[0]とpのアドレスは一致している。つまり、cl[0]とpは全く同じものとして扱われる。

>>> cl[0].age=16
>>> p.age
16

#ほらね。cl[0]にageプロパティを追加すると、pにも同じプロパティが存在するようになる。

Python ― 漬物

Python(2.5)のシェル IDLE で遊んでみた。

Pythonにはオブジェクトのインスタンスを、漬物文字列に変換したり、ファイルに保存するために、pickleというモジュールがある。JavaやC#にも似たような機能があるのだが、手軽さでPythonのpickleには及ばない。

まずは、「import pickle」でpickleモジュールをインポートする。すると、「pickle.dumps(X)」でXを漬物にできる。

  • pickle.dumps(1) → 'I1\n.' #整数1の漬物
  • pickle.dumps('1') → "S'1'\np0\n." #文字「1」の漬物
  • a = [1,2,3]
    pickle.dumps(a) → '(lp0\nI1\naI2\naI3\na.' #リストaの漬物
  • class unko:
        def __init__(self,jotai):
            self.jotai = jotai
    a = unko('dorodoro')
    pickle.dumps(a) → "(i__main__\nunko\np0\n(dp1\nS'jotai'\np2\nS'dorodoro'\np3\nsb." #jotaiが'dorodoro'であるunkoの漬物)
    pickle.dumps(unko) → 'c__main__\nunko\np0\n.' #あれぇ? unkoの漬物であるはずだが、unkoにjotaiプロパティがあることなどなどは含まれていない。単に名前だけ。
  • pickle.dumps(pickle.dumps) → 'cpickle\ndumps\np0\n.' #pickle.dumpsそのものの漬物のはずだが、これも名前だけ。

クラスのインスタンスは漬物にできるが、クラスそのものは本物の漬物にはできない。モジュールに含まれるメソッドも無理。