ファイルロックを使った Mutex というか排他処理というか。

例えば cron で定期的に重い処理を呼び出していて、前回の処理が終了していなかった場合は、何もせず終了させたいというとき。
flock() ならプロセスが (異常だろうと何だろうと) 終了すればロックが外れた状態になるので、それ使って判定できれば楽だなと思った。


ので、作ってみた。

続きを読む

配列演算子オーバーロードもしくは PHP 5 の配列エミュレート機能全般

正確にはオーバーロードじゃないけど。
PHP でも [] でアクセスできるクラス作れたんだね。

参考

PHP: ArrayObject - Manual
分かりやすい実装例。
PHP: オブジェクトのイタレーション - Manual
イテレータについて全般。
SPL-StandardPHPLibrary
詳細なリファレンス。インターフェースのリファレンスが見つからないときに。
続きを読む

クラスの挙動まとめ #2

前回 クラスの挙動まとめ #1

内容
関数とメソッドの違い


以降は、新形式クラスのみに焦点を当てる。
中には旧形式クラスにも適用される動作もあるけど、無視する。区別が面倒だから。


オブジェクトを比較する際に == と is を使い分けているけど、理由があるので無視するように。
理由は最後のほうのおまけに書いてある。
それぞれの違いは、 Python リファレンスマニュアル - 5.9 比較 (comparison) を参照。
簡単にいうと

is
厳密な一致。同一のオブジェクトを指している場合に True 。オーバーロード不可
==
緩い一致。意味的に同一な場合に True 。オーバーロード


なお、このエントリーに書かれている全ての例において、

  • is が True ならば == も True である
  • == が False ならば is も False である

の 2 つが成立している。
よって、 is が True な場合、もしくは == が False の場合、もう一方での比較結果は省略する。*1

関数 (function) とメソッド (method) の違い

Python では関数とメソッドもオブジェクトであることを理解しておく。

# 関数
def func(self):
    print self, "Function"

# クラス
class C(object):
    def method(self):
        print self, "Method"

# インスタンス
obj = C()

func       # <function func at アドレス>
C.method   # <unbound method C.method>
obj.method # <bound method C.method of <__main__.C object at アドレス>>
C.method == obj.method # False

C.func = func
obj.another = func

C.func   # <unbound method C.func>
obj.func # <bound method C.func of <__main__.C object at アドレス>>
obj.another # <function func at アドレス>
C.func == func      # False
obj.func == func    # False
obj.another is func # True

import types

isinstance(func, types.FunctionType)   # True
isinstance(C.func, types.MethodType)   # True
isinstance(obj.func, types.MethodType) # True

このように、関数とメソッドは違うものとして扱われている。
中でも、関数オブジェクトをクラスオブジェクトのプロパティへ代入すると、メソッドオブジェクトに変換されることに気をつける。

*1:これだから演算子オーバーロードは嫌いだ

続きを読む

[Python] クラスの挙動まとめ #1

内容
クラスの基本的な挙動、新形式クラス、 type() を使ったクラス生成
対象
ある程度プログラミングの知識がある人。

クラスもオブジェクト

Python ではクラスもオブジェクトである。

class Class:
    """クラスオブジェクトを作成するリテラル

    Class という変数に "Class という名前のクラス" のオブジェクトを代入している
    """
    pass

id(Class)        # オブジェクトのアドレス
Class.__module__ # オブジェクトの属性にアクセスしている
Class.__name__   # クラスオブジェクトのプロパティ __name__ にはクラス名が入っている。ここでは 'Class'

Another = Class  # 変数だから、代入もできる
Another.__name__ # 'Class'
obj = Another()
isinstance(obj, Class)   # True
isinstance(obj, Another) # True
obj.__class__.__name__   # 'Class'
# Another という変数に入っている "Class という名前のクラス" のオブジェクトを呼び出し、インスタンスを作成している。

"""
重要なこと

obj = Class()
で obj に Class のインスタンスが代入されている。
これは、他の言語で
obj = new Class()
としているのとは全く違う意味。

Class() は、 Class という変数に入っているオブジェクトを呼び出している
(__call__ プロパティの関数をコールしている) だけである。

この場合、 Class に入っているのは "Class という名前のクラス" のオブジェクトである。
このオブジェクトの __call__ を呼び出し、__call__ の中でインスタンスを生成し、それを呼び出し元に返しているに過ぎない。

ようするに、
obj = Class()
obj = Class.__call__()
は同じ意味である。
(細かいところで違うし、実際上のコードはエラーがでるけど、その部分はまた後で)

この理解は後にメタクラスを学習する際に役立つ。
"""

なお、 __call__ については Python ライブラリリファレンス - 3.3.4 呼び出し可能オブジェクトをエミュレートする を参照。

続きを読む