17 November 2008

ノート: instant python

前回のinstant hackingに引き続き、instant pythonも読みました。その際のノートです。

hetland.org : Instant Python

なお途中の「Objects and Stuff…」までです。「A Jedi Mind Trick」以降はまた次回。


The basics

インデントでブロックを表現するよとか、データ構造とか、基本的なこと。割愛。

Functions

関数について。

  • 引数は値渡し
    • ローカル変数のスコープの話など。関数内のローカル変数の値を変更しても、関数の外には影響しない。まあ直感的ですね
  • 関数を変数に入れたりできる(関数オブジェクト?)。関数型言語っぽい。
def square(x):
    return x*x

queeble = square
print queeble(2) # Prints out 4

Objects and Stuff…

クラスとオブジェクトについて。

class Basket:

    # Always remember the *self* argument
    def __init__(self,contents=None):
        self.contents = contents or []

    def add(self,element):
        self.contents.append(element)

    def print_me(self):
        result = “”
        for element in self.contents:
            result = result + ” ” + `element`
        print “Contains:”+result
  • すべてのメソッドの最初の引数に、オブジェクト自身をあらわすselfをいれる
  • メソッドはこんな風につかう:object.method(arg1,arg2)
  • __init__というメソッドはコンストラクタ
  • 引数にデフォルト値を与えることもできる。(上の例だとコンストラクタの引数contents)
  • short-circuit logic。詳しくは後述
  • バッククオート(`)でオブジェクトを囲うと、文字列表現になる
  • 「+」演算子はリストや文字列に対して使える
short-circuit logicについて

pythonでは、[]、0、""などの「空要素」は「偽」、その他の要素([0]、1、"hello world"など)は「真」になる。ここで、たとえば「a and b」という表現は、次のように評価される:

  • aの真偽をチェック
  • 偽なら、aを返す
  • 真なら、bを返す

逆に、「a or b」ならば、次のように評価される:

  • aの真偽をチェック
  • 真なら、aを返す
  • 偽なら、bを返す

たとえば、「print a or b」をif-elseで実現すると、次のようになる:

if a:
    print a
else:
    print b

これが「short-circuit logic」


ここで上記の例を考えてみる。コンストラクタ__init__の引数contentsに、値が渡されたかどうかで動作が変わる。short-circuitではなく、else-ifで再現した場合、

if contents:
    self.contents = contents
else:
    self.contents = []

となる。ここで、contentsのデフォルト値を[]にすれば、こんな面倒な処理をしなくてよい気がするが、わざわざこのように実装しているのはなぜだろうか。python処理系は、デフォルトの値として、別のBasketクラスのインスタンスにも、全く同じ空リストを渡してしまう。つまり、インスタンスAのリストの内容を変更したとすると、その後に作ったインスタンスBのcontentsの中身も変化してしまう。よってこのような実装になっている。このへんのことは、ドキュメントで、 identityとequalityの違いについて調べると良い。

また、こういう実現法もある。

def __init__(self, contents=[]):
    self.contents = contents[:]

[:]は単に全要素をコピーしている。

クラスの利用
b = Basket([‘apple’,’orange’])
b.add(“lemon”)
b.print_me()

ふつうですね。

__str___

__str__は、インスタンスが文字列のように扱われたときの動作を定義する。たとえば、

def __str__(self):
    result = “”
    for element in self.contents:
        result = result + ” ” + `element`
    return “Contains:”+result

と定義しておき、

print b

とすることで、最初の例のprint_me()メソッドと同様の動きをする。

継承

Basketクラスの子クラスSpamBasketを作るには、こうする:

class SpamBasket(Basket):
    # …

pythonでは多重継承(複数の親クラスを持つこと)ができる。その際は、括弧のなかでコンマ区切りで親クラスを列挙する。

コンストラクタの中から、親クラスのコンストラクタを呼ぶことができる。たとえば、SpamBasketのコンストラクタの中から、Basketのコンストラクタを呼ぶには、

Basket.__init__(self)

とする。

pythonでのオブジェクト指向プログラミングについては、チュートリアルの9章を参考にすると良い。



続く…