Pythonでは「クラスもオブジェクト」です

WIKI WIKI SHUTTLE

 今日も見にきてくださって、ありがとうございます。がんばって更新していきます。

 ずっとデータベースの論理設計の勉強会に参加しているのですけど、そちらでしばらくPythonの勉強会をすることになりました。メンバーのなかでは適任者ということで講師に任命されまして、それで先日、第一回目が開催されました。その講習の中でぼくが「Pythonでは、すべてがオブジェクトとして管理されています。」と説明してから、ふと、class作成後、class変更したら、以前のclassとは異なるオブジェクトになっているのだろうか、ということが自分でも気になったので、確認してみました。でも、このタイトルだと、なんのこっちゃ、という感じですねぇ♪

 まず、オブジェクトとはこんな感じのモノです、というイメージがわかりやすいように、listを作成してみます。ご覧のとおり、typeはlistになり、オブジェクトとして管理するためにidが採番されています。

>>> alist = [1,2,3,4,5]
>>> type(alist)
<class 'list'>
>>> id(alist)
3005538914888
>>>
http://pythontutor.com/visualize.html#mode=display
にてイメージ化。

 ちなみに、この中で使われている「1」などの数値もオブジェクトとして管理されています。調べていて面白かったのは、-5~256の範囲の数値はintのオブジェクトとしてあらかじめキャッシュされて使いまわされているそうです。この点は処理系によって実装は異なるのでしょうけど、ぼくの環境では以下のように確かに使いまわされているのが確認できました。

>>> type(1)
<class 'int'>
>>> id(1)
140729051148544
>>> id(alist[0])
140729051148544
>>> id(2)
140729051148576
>>> id(1+1)
140729051148576
>>> id(alist[1])
140729051148576

 では、本題のclassを定義して確認してみます。以下のようなスクリプトを実行してみます。poiクラスを作成してidを確認してから、内容を少し変更したpoiクラスを再作成してもう一度idを確認してみます。

class poi:
    pass

print(type(poi))
print(id(poi))

class poi:
    a = 1

print(type(poi))
print(id(poi)) 
一つ目のクラス
二つ目のクラス

printの実行結果は、以下の通りでした。やっぱり違うモノ(オブジェクト)になってますよね。

出力結果

 ちょっと意外に感じたのは、class定義されたもののtypeが「type」だったことです。やっぱり、<class ‘class’>はちょっとヘンだよねぇ、ということにでもなったのでしょうか?このあたりの呼び名は宗教観(?)の違いで争われそうですね。
 idは予想通り異なっていたので、class定義することで、以前のクラスが別のオブジェクトで上書きされた、という風に考えられますね。あ、、、でも、上書きではありませんでしたね。自分で説明しておいて間違えました。変数名は、オブジェクトに張り付けた付箋のようなイメージです、と説明したのでした。実際にはpoiクラスというクラスのオブジェクトができて、再度、別のpoiクラスというクラスのオブジェクトができる、というのが正しい考え方ですね。ちょっと変数にセットしてみてやってみます。

class poi:
     pass

poiA = poi

class poi:
    a = 1

poiB = poi
クラスが作成されるごとに変数へ格納

 予想通り、「poi class」というオブジェクトが二つできました。先ほどの例ではpoiAに代入しなかったので、最初の「poi class」オブジェクトがガベージコレクトされて捨てられてしまった、ということですね。

xdwlibでDocuworks9の中のテキストを出力

 今日も見にきてくれて、ありがとう。久しぶりの更新です。そのうちまた更新しますので、また見にきてくださいね。

 おしごとの関連で富士ゼロックスさんのドキュワークスでつくられた文書のテキストを抜き出す必要があったので、Pythonスクリプト作成してみました。帳票出力のプログラムを修正したときに、修正前後の差分をとって、チェックするのに便利です。
ご利用は自己責任でどうぞ。

利用するまでに必要な作業は以下の通りです。

1.Pythonのインストール
  これは、本家のサイトをご覧になってがんばってやってください。
  ぼくの環境は、実行時最新の3.7.4をインストールしました。

2.xdwlibのインストール
  「pip install xdwlib」で完了。3.8.2.0がインストールされました。なぜかインストール時にエラーがでましたけど、正常に利用できました。林秀樹さん、ありがとうございます。

from sys import argv, exit
from os.path import basename, isfile, splitext
from xdwlib import xdwopen

def export_xdwfulltext(input_file):

    BASE_FILENAME , ext = splitext(input_file)
    if ext.lower() != ".xdw":
        print("指定されたファイルの拡張子が.xdwではありません。["+ext+"]")
        input("Hit Enter key.")
        return

    if not isfile(input_file):
        print("指定されたファイルが存在しません。["+input_file+"]")
        input("Hit Enter key.")
        return

    OUTPUT_PATHNAME = BASE_FILENAME + ".txt"

    if isfile(OUTPUT_PATHNAME):
        print("出力先のファイルが既に存在します。["+OUTPUT_PATHNAME+"]")
        answer = input("上書きしますか?(Y/N):")
        if answer.upper()[0] != "Y":
            print("処理を中断しました。")
            return

    with open(OUTPUT_PATHNAME,"w",encoding="utf-8") as f,\
         xdwopen(input_file) as doc:
        for p in doc:
            f.write(p.fulltext())
            f.write("\n")


if __name__ == '__main__':

    if len(argv) < 2:
        print(basename(argv[0]),"は、ドキュワークスで出力されたxdwファイルの中のテキストを出力するプログラムです。")
        print("拡張子が.xdwのファイルのみ対象とし、同ファイル名の.txtファイルとして出力します。")
        print("使い方1:",basename(argv[0]),"hoge.xdw ...")
        print("使い方2:",basename(argv[0]),"に、ファイルをドラッグ&ドロップ")
        input("Hit Enter key.")
        exit

    for f in argv[1:]:
        export_xdwfulltext(f)