Python初心者メモ（その２）

Pythonでもっと遊んでもう少し学んだので、[前回](http://qiita.com/ota-meshi/items/3f14dae4447af7cd04b2)の続きとして書きます。

関係ないですけど、Python使いのことはPythonistaって言うんですね。
めざせPythonista！！

# 配列系
## 要素アクセス

普通の

```py3
items = ["A", "B", "C", "D", "E"]
item = items[1] # インデックス1の要素を取得
print(item) # B
```

最近学んだ

```py3
items = ["A", "B", "C", "D", "E"]
item = items[-1] # 最後のの要素を取得
# item = items[len(items) - 1] # こんなことしなくてもいい
print(item) # E
```
-2を指定したら後ろから2番目"D"が取れる

## 配列コピー

[前回](http://qiita.com/ota-meshi/items/3f14dae4447af7cd04b2)も書いたけどこんな感じ。

```py3
items = ["A", "B", "C", "D", "E"]
items2 = items[1:3] # index 1から2を抽出したlist生成
print(items2) # ['B', 'C']

items3 = items[1:] # index 1から後ろ全部を抽出したlist生成
print(items3) # ['B', 'C', 'D', 'E']

items4 = items[:3] # index 3からより前全部を抽出したlist生成
print(items4) # ['A', 'B', 'C']
```

さらに、飛び飛びでとることもできる。

```py3
items = ["A", "B", "C", "D", "E", "F", "G"]
items6 = items[::2] # 1つ飛ばしで抽出したlist生成
print(items6) # ['A', 'C', 'E', 'G']

items7 = items[::-1] # 逆順のlist生成
print(items7) # ['G', 'F', 'E', 'D', 'C', 'B', 'A']

items8 = items[-1:3:-1] # 逆順でindex範囲を指定するなら開始を後ろにする。（逆にすると要素が取れない）
print(items8) # ['G', 'F', 'E']
```

## for文

当然だが`[::]`を使って配列のループが色々できる

```py3
items = ["A", "B", "C", "D", "E", "F", "G"]
for item in items[1:]:
    print(item) # B,C,D,E,F,Gを順番にprint

print("---")

for item in items[::-1]:
    print(item) # G,F,E,D,C,B,Aを順番にprint

print("---")

for item in items[::3]:
    print(item) # A,D,Gを順番にprint
```

### for文でindexもとる
やり方があった。

```py3
items = ["A", "B", "C", "D", "E"]

for i, value in enumerate(items):
    print(str(i) + ":"+ value)
```
結果

```
0:A
1:B
2:C
3:D
4:E
```

### リストの内包表記
（for文とは別物かも）
http://docs.python.jp/3.5/tutorial/datastructures.html#list-comprehensions

配列の中身を操作して別の配列を作りたいとき

```py3
items = ["a", "B", "c", "D", "e"]

# 大文字にしたlistを作る
items2 = []
for item in items:
    items2.append(item.upper())

print(items2) # ['A', 'B', 'C', 'D', 'E']
```

て書きそうなところ、items2を作るループの処理は、下記のように書ける。

```py3
items2 = [item.upper() for item in items]
```


ちなみにmapを利用すると、下記のように書ける。

```py3
items2 = list(map(str.upper, items))
```


さらに、

```py3
items = ["a", "B", "c", "D", "e"]

# 大文字だけのlistを作る
items2 = []
for item in items:
    if item.upper() == item:
        items2.append(item)

print(items2) # ['B', 'D']
```

て書きそうなところ、items2を作るループの処理は、下記のように書ける。

```py3
items2 = [item for item in items if item.upper() == item]
```

## 結合
個人的に結構感動するPythonの配列結合
なんと`+`演算子だけでできた。

```py3
item1 = ["A", "B", "C"]
item2 = ["D", "E"]

item3 = item1 + item2
print(item3) # ['A', 'B', 'C', 'D', 'E']
```
（extendと違って別のlistが作られる）

予想できるが当然、加算代入も可能

```py3
item1 = ["A", "B", "C"]
item2 = ["D", "E"]

item1 += item2
# item1.extend(item2)と結果は同じ
print(item1) # ['A', 'B', 'C', 'D', 'E']
```
<br>

そして個人的に全く理解できないのがある。

```py3
item1 = ["A", "B", "C"]
item2 = ["D", "E"]

item1[:0] = item2
print(item1) # ['D', 'E', 'A', 'B', 'C']
```
上記のように書くと頭に結合できる。

慣れない僕はさすがに理解できないので当分は、

```py3
item1 = item2 + item1
```
と書くと思う。


# 文字列操作

## join
（[前回](http://qiita.com/ota-meshi/items/3f14dae4447af7cd04b2)書いておくべきだった内容かも）

```py3
s = ":".join(["A", "B", "C", "D", "E"])

print(s) # "A:B:C:D:E"
```

## 繰り返し
これも個人的に結構感動してる方法。
なんと`*`演算子だけでできた。（これ知るまでループ書いてた）

```py3
s = "あ" * 5
print(s) # あああああ
```

# lambda式

こう書く。lambda式の書き方自体は、今となってはJavaとあまり変わらない。

```py3
func = lambda x: x.upper()

print(func("a")) # A
```


# 条件文

## in
配列に含まれるかどうかを判定（したり）する。（dictだとまた動作が違う）
orで繋がなくていい便利なやつ。

http://docs.python.jp/3.5/reference/expressions.html#membership-test-operations
帰属検査演算という名前らしい。
SQLのINみたいな？[神殿マークの言語](https://ja.wikipedia.org/wiki/Delphi)でもできたなぁという個人的思い出。

```py3
if 2 in [1, 2, 3]: # True
    print("2がある")

if 4 not in [1, 2, 3]: # True
    print("4はない")
```


# yield 

http://docs.python.jp/3.5/reference/expressions.html#yieldexpr
http://docs.python.jp/3.5/reference/simple_stmts.html#the-yield-statement

yieldが何なのかの説明はできないので下記を参考
https://ja.wikipedia.org/wiki/ジェネレータ_(プログラミング)

JavaでいうIteratorを、簡単に作る仕組みと勝手に理解した。


```py3
def yield_sample():
    for i in [1, 2, 3]:
        yield i

gen = yield_sample()

print(next(gen))  # 1
print(next(gen))  # 2
print(next(gen))  # 3
print(next(gen))  # StopIteration
```

```py3
for i in yield_sample(): # for文で回せる
    print(i)  # 1、2、3を順番に出力
```

次がyieldの面白いところ

```py3
def yield_sample2():
    print("つぎは1")
    yield 1
    print("つぎは2")
    yield 2
    print("つぎは3")
    yield 3
    print("つぎはない")

for i in yield_sample2():
    print(i)  # 1、2、3を順番に出力するが、、、
```

結果はこう

```
つぎは1
1
つぎは2
2
つぎは3
3
つぎはない
```

yieldで作成したジェネレータをlistにしたい場合はこう

```py3
def yield_sample():
    for i in [1, 2, 3]:
        yield i

l = list(yield_sample())
print(l) # [1, 2, 3]
```

# ファイル操作系

ググったほうが早いかも。いくつかやり方がある印象を受けた。
どの方法が最も良いのかまではわからない。
ファイル操作系全部は書かないけど、自分が使ったものだけ書いておく。

## 読み込み

```py3
f = codecs.open(path, "r", "utf-8")
ret = f.read()
f.close()
```

## 書き込み
```py3
f = codecs.open(path,"w", "utf-8")
f.write(value)
f.close()
```

## ファイル存在
```py3
if os.path.exists(path):
```

## フォルダ掘る
```py3
os.makedirs(dirPath)
```

## 親フォルダ名取得

```py3
os.path.dirname(path)
```

## ディレクトリからファイルのリストアップ

```py3
for root, _, files in os.walk(dirPath):
    for fileName in files:
        path = os.path.join(root, fileName)
        yield path
```

# 例外処理

## except
Javaでいうcatchブロック

```py3
def error_throw():
    "" + 1

try:
    error_throw()
    print("ここにはこない")
except: # すべてのエラーでここに来る
    print("エラー")
```

## catch的なやつ

```py3
try:
    error_throw()
    print("ここにはこない")
except Exception as e: # エラーObjectを取得
    print(type(e))
    print(e)
```
結果

```
<class 'TypeError'>
Can't convert 'int' object to str implicitly
```

Exceptionの型別にもかける

```py3
try:
    error_throw()
    print("ここにはこない")
except ValueError:
    print("ValueErrorは発生しないのでここにはこない")
except TypeError:
    print("TypeErrorが発生するのでここにくる")
```

## trace
Javaでいうstacktraceてきなやつ

```py3
import traceback

try:
    error_throw()
except :
    print(traceback.format_exc())
```

# クロージャ
できない。ざんねん。Javaと似たイメージでできない。

```py3
def new_counter():
    count = 0
    def func():
        count += 1
        return count
    return func

c = new_counter()
print(c())
print(c())
print(c())
```
エラー

```
UnboundLocalError: local variable 'count' referenced before assignment
```
下記のように書けばそれっぽいことができる。。。（Javaみたい）

```py3
def new_counter():
    count = [0]
    def func():
        count[0] += 1
        return count[0]
    return func

c = new_counter()
print(c())
print(c())
print(c())
```

# テスト

## 作成
Eclipseから「新規」→「Pydevモジュール」→名前を付けて「完了」→
「モジュール：Unittest」を選択して「OK」で出来たものをみればなんとなく書き方がわかると思う。

### 実行
「実行」→「Pythonユニットテスト」で実行できる。

### サンプル
```py3
import unittest


class Test(unittest.TestCase):


    def testName(self):
        self.assertEqual(1, 2, "サンプル")


if __name__ == "__main__":
    #import sys;sys.argv = ['', 'Test.testName']
    unittest.main()
```
結果

```
F
======================================================================
FAIL: testName (__main__.Test)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\hogehoge\testsample.py", line 13, in testName
    self.assertEqual(1, 2, "サンプル")
AssertionError: 1 != 2 : サンプル

----------------------------------------------------------------------
Ran 1 test in 0.016s

FAILED (failures=1)
```

## テストの動的追加

下記を参考にしました。
http://hirokazumiyaji.hatenablog.com/entry/2015/07/16/134238

下記サンプルはディレクトリにあるファイル分のテストを登録するサンプルです。

```py3
import unittest
import os


class Test(unittest.TestCase):
    # 空のテストクラス
    pass

def setup_testsuite():
    """
        ディレクトリのファイルをリストアップしてテストを登録
    """
    root = os.getcwd()
    test_files_dir = os.path.join(root, "files") # このpyファイルの隣にあるfilesフォルダの中のファイルをターゲットにする

    def listup():
        for root, _, files in os.walk(test_files_dir):
            for file_name in files:
                if os.path.splitext(file_name)[1].lower() == ".txt":# 拡張子で絞り込み
                    yield file_name, os.path.join(root, file_name)

    for file_name, path in listup():
        def create_test_func(file_name, path):
            def test_func(self):
                """
                    テストの実態
                """
                print("test start: " + file_name)

                # selfはTestなのでassertEqualは下記のように呼ぶ
                # self.assertEqual(first, second, msg)

            return test_func

        test_name = "test_{}".format(file_name)
        setattr(Test, test_name, create_test_func(file_name, path)) #登録

# テストの登録を実行
setup_testsuite()

if __name__ == "__main__":
    # import sys;sys.argv = ['', 'Test.testName']
    unittest.main()
```