Python 基礎文法（雑）めも (4)


2.7ベース。
何らかの他言語を知っている前提です。

## 関連
- [(1)](http://qiita.com/kazoo/items/762c98bb3d1491105bb1)
- [(2)](http://qiita.com/kazoo/items/a4fbd3ab5832b71aae82)
- [(3)](http://qiita.com/kazoo/items/8a6388c0a6ed0d973ea5)

## モジュールとクラス
### from import
「decimal という標準モジュールから Decimal クラスを使う」宣言

```python
>>> from decimal import Decimal

てのクラスを import
>>> d = Decimal(10)
>>> print d
10

>>> print d + 3  # Decimal クラスが+演算子に対応するメソッドを持っている
13
```

Decimal について詳細は http://docs.python.jp/2/library/decimal.html

### クラス定義

``` python
>>> class MyClass:
...	    pass
...
>>> mc = MyClass()
>>> print mc
<__main__.MyClass instance at 0x1076245a8>
```

クラス名は通常キャメルケースで書く。pass は Null Operation であり、何もしない。

### アトリビュート
Python には、クラス定義とともにメンバ変数の定義を記述する、という機能はない。
アトリビュート（データメンバ）は、生成したインスタンスに対してドット区切りで変数に代入することで、そのインスタンスごとに定義される。

``` python
>>> mc = MyClass()
>>> mc.value = 10
>>> print(mc.value)
10

>>> mc2 = MyClass()
>>> print mc2.value
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: MyClass instance has no attribute 'value'
```

### メソッド定義と \__init__
コンストラクタ的な初期化メソッドとして、\__init__(と、\__new__ ）が用意されている。

```python
class MyClass:
    # 初期化メソッド
    def __init__(self):
        self.h = 'hoge'   # アトリビュートを追加
        
    # メソッド
    def print_h(self):
        print h
        
mc = MyClass()
mc.print_h()  # => 'hoge'
```

第1引数の self にはインスタンスオブジェクト自体が渡される。慣習的に self を使うが、this でも me でも動く。初期化時に変数を与えたい場合は、

```python
class Rect:
    def __init__(self, width, height):
        self.width = width
        self.height = height
        
    def area(self):
        return self.width * self.height
        
r = Rect(100, 50)
print r.height  # => 50
print r.area    # => 5000
```
のようになる。初期化メソッドの呼び出し側では第1引数を無視していることに注意。引数に self を忘れると、

```
>>> class MyClass():
...     def hoge():
...         print 'hoge'
...
>>> mc = MyClass()
>>> mc.hoge()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: hoge() takes no arguments (1 given)
```
というエラーになる。

### カプセル化
python には private キーワード等はなく、アトリビュートやメソッド名を隠蔽したい時には、その前にアンダースコアを（1つまたは2つ）付ける。

```
def _private_method():
    # ....
    
def __secret_method():
    # ....
```
1つの場合は慣習的に「外部から呼ばないでね」という意思を表し、2つの場合は内部で自動的に名前を改変し、外部から呼び出し不可能にする。

```
class MyClass:
    def __init__(self, size):
        self._size = size
        self.__size = size

mc = MyClass(100)
print mc._size    # => 100
print mc.__size   # => AttributeError
```

## クラスの継承
Python は **多重継承** に対応している。また、数値や文字列などの組み込み型を継承して新しいクラスを作ることもできる。

### 定義
	class <クラス名>(スーパークラス名 [, スーパークラス2, スーパークラス3,,]):

継承するクラスを指定しなかった場合と object を継承した場合で微妙に挙動が違うらしい。何も継承しない場合は object を継承することが推奨されている(？)。

Python3 では親クラスの指定がない場合は標準で object を継承するようになる模様。

```python
class C1(): 
    pass
print dir(C1) #=> ['__doc__', '__module__']

class C2(object): 
    pass
print dir(C2) #=> ['__class__', '__delattr__', '__dict__', '__doc__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', '__weakref__']
```

### オーバーライドと super			
```python
class Rectangle(object):
    def __init__(self, w, h):
        self.w = w
        self.h = h
        self.color = 'red'
  
    def area(self):
        return self.w * self.h
      
      
class Square(Rectangle):     
    # 初期化メソッドを再定義（オーバーライド）
    def __init__(self, length):
        self.w = self.h = length

s = Square(100)
print s.area()   #=> 10000、親クラスのメソッド呼び出し
```

メソッドのオーバーライドは完全な上書きになり、また親のコンストラクタを自動で呼び出すような動きもしない。
なので、例えば上記で親クラスの \__init__() で初期化された変数 color が、Square クラスのインスタンスには存在しないことになる。
それを防ぐためには super() で親のメソッドを呼び出すが、

```python
class Square(Rectangle):
    def __init__(self, length):
        super(Square, self).__init__(length, length)
```

…というめんどい呼び方をしなくてはならない。自分の型と self を渡して親クラスを特定する。また、このとき親クラスが object クラスを継承していないとエラーになる。

Python3 では `super()` だけでスーパークラスを取得できる、らしい。