Pythonをはじめる

「そういえばPython触ったことない。」
そんなことを思い、「はじめてのPython」を買って流し読みなどをしています。
ひとまず読んで動かして試したところまで。

不変なオブジェクト

  • 数値
  • 文字列
  • タプル

タプルが印象的。
あと、文字列が不変なのもRubyとの対比で印象的だった。

>>> str = "abcde"
>>> str[0]
'a'
>>> str[0] = "a"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment

エラーになる。


Rubyは可変なので、同じようなことを書いても通る。

irb(main):001:0> str = "abcde"
=> "abcde"
irb(main):002:0> str[0]
=> "a"
irb(main):003:0> str[0] = "A"
=> "A"
irb(main):004:0> str
=> "Abcde"

可変なオブジェクト

  • リスト
  • ディクショナリ

真偽値

  • True
    • 0以外の数値
    • 空以外のオブジェクト
  • False
    • 数値の0
    • 空オブジェクト(空リストとか空ディクショナリとか)
    • None
      • Noneは特殊なオブジェクト
評価はショートサーキット評価
>>> def busy():
      while True : print("hello")
>>> if True or busy(): "True"
'True'

型のカテゴリ

型はカテゴリに分けることができ、同じカテゴリの型はほぼ同じような操作ができる。

  • 数値
    • 加算・乗算などの算術演算ができる。
    • 数値型や、集合型等が数値。
>>> s0 = set("abcde")
>>> s1 = set("ace")
>>> s0 - s1
set(['b', 'd'])
  • シーケンス
    • オブジェクトを一定の順序に並べたもの。
    • 文字列、タプル、リスト等がシーケンス。
    • インデクシング・スライシング・連結などができる。
>>> for i in [0,1,2,3,4] : print i ** 2
...
0
1
4
9
16
  • 写像
    • キーによるインデクシングなどができる。
    • ディクショナリが該当。

リスト内包表記

  • 全要素に同じ演算をおこなう。
  • 最後に新たなリストを返す。(一番外側が[]になっているのは、リストが返ることを示している)
  • コードが簡潔になる。
  • 実行速度が速いらしい。
>>> q = [ x ** 2 for x in [0,1,2,3,4,5] if x % 2 == 0]
>>> for i in q: print(i)
...
0
4
16

同じようなことをLINQで書くとこうかな、と。(Main関数とかの部分は省略)

            var q = from i in new double[] { 0, 1, 2, 3, 4, 5 }
                    where i % 2 == 0
                    select Math.Pow(i, 2);
            foreach (int i in q) Console.WriteLine(i);

変数とオブジェクト

  • 変数はオブジェクトへの参照
  • オブジェクトは2つのヘッダを持つ
    • 型識別子
    • リファレンスカウンタ

PythonはReferenceCountGC。Rubyはmark-and-sweepGC。
オブジェクトに型識別子が付加されていて、変数はオブジェクトへの参照だけ持つっていう構成は、CLRと同じだな。

同等と同一

  • 同等
    • 両オブジェクトが同じ値を有している
    • ==演算子で比較
  • 同一
    • オブジェクトリファレンスが同じ
    • is演算子で比較
同一とキャッシュ

小さい数値や文字列はキャッシュされ再利用されるため、同一のリファレンスになる。

>>> str0 = "abcde"
>>> str1 = "abcde"
>>> str0 is str1
True

文字列を扱う上でのメモリ効率という観点で言えば、確かCLRでも"文字列のインターン化"をやってるから同じような現象になるのではと、手元のC#3.0で試す。

            string str0 = "abcde";
            string str1 = "abcde";
            Console.WriteLine(string.ReferenceEquals(str0, str1));

実行するとコンソールにはTrueと表示された。
(CLR2.0では文字列リテラルは全てインターン化される)

こう書くとFalseになる。

            string str0 = "abcde";
            System.Text.StringBuilder builder = new System.Text.StringBuilder();
            builder.Append("abc");
            builder.Append("de");
            string str1 = builder.ToString();
            Console.WriteLine(string.ReferenceEquals(str0, str1));

じゃあRubyはというと、Falseになった。

irb(main):010:0> str0 = "abcde"
=> "abcde"
irb(main):011:0> str1 = "abcde"
=> "abcde"
irb(main):012:0> str0.equal? str1
=> false

多分、Rubyの文字列が「可変」だから。
「不変」という縛りがあってはじめて、インターン化やキャッシュのように「同じオブジェクトを指す」という方法が可能になる…ということかな。

ステートメント

先に文法だけかじり読み。

  • 複合ステートメントを作る場合、見出し行にコロン(:)をつける。
  • ブロックの区切りは字下げで表現する。
>>> for i in [1,2,3,4,5]:
...     print i
...     print i ** 2
...     print i ** 3
...
1
1
1
2
4
8
3
9
27
4
16
64
5
25
125

雑感

  • 書き方がかなり強制されるけど、余計な括弧を書かなくていいというメリットはそれに見合っている気がする。
  • コロン付けるのも、見出し行の判定とか意味が付属しているから、あまり気にならない。
  • 「はじめてのPython」の本から情報得ているからかもしれないけれど、カテゴリにしろビルトインオブジェクトにしろ、型とかの扱いが綺麗に整頓されている印象を持った。
  • 言語を幾つか並べて比べるってやり方は、結構面白いし、それぞれの特徴が印象に残るから、よいやり方だなと感じた。