Python基礎基礎講座　CSV処理（関数とクラス其の壱　CSVを読込んで書き出す。）

<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script language="JavaScript">
$(document).ready( function () {
   $("a[href^='http']:not([href*='" + location.hostname + "'])").attr('target', '_blank');
})
</script>

この記事は、Django Girls Japan およびelvでのPython初級者向け、
勉強会用資料です。尚、記載者も初心者のため、何らかの不具合などござましたら申し訳ございません。

記載者環境：Windows 10  python3.5

このページはCSVを読込んで、別のフォーマットで吐き出す基本的な手順を
順を追って説明するページです。
まずはクラスを作る前に、最初から最後までの処理をつらつらと書いてみます。

### 今回作成したファイルを実行するとこうなるよ
今回は読込んだCSV(addresslist.csv)を以下の形式にして
別のCSVファイル(allcodelist.csv)として書き出します。
***
住所や電話番号は適当な情報です
***
**addresslist.csv**
![6.JPG](https://qiita-image-store.s3.amazonaws.com/0/100769/fc7bc0d9-c448-9527-0a96-6f248acf73a7.jpeg)

**allcodelist.csv**
![5.JPG](https://qiita-image-store.s3.amazonaws.com/0/100769/7bff588c-4b32-82af-fb7f-e5196ba337e6.jpeg)




# フォルダを作成しよう
まずは下準備です。任意の場所に新規でフォルダを作成します。
コマンドラインで（コマンドライの開き方は[こちら](http://qiita.com/sandream/items/a0f69e69b561192517a2)
フォルダを作りたい場所へ移動したら、**mkdir フォルダ名**と入力します。
今回は、address　というフォルダを作成します。

```python
mkdir address
```

### 準備2
作成したフォルダにテキストエディタに以下を記載し、
pythonファイルを保存します。

```python
# -*- coding: utf-8 -*-
#!/usr/bin/env python
```
ファイルの冒頭には上記を記載してください。
（上記内容の説明はここでは省きます。）
ファイルに名前をつけて、.py の拡張子で保存します。
（文字コードはutf-8にします。）
テキストエディタ　は色々ありますが記事者は[ATOM](https://atom.io/)を利用しています。

# CSVを読込む
### CSVデータを開いてデータを受け取る
それでは、準備が整いましたので、csvを読込んでみましょう。
**変数 = open(読込みたいファイルのパス, "r")**
でファイルデータを読込む事ができます。

```python
# -*- coding: utf-8 -*-
# !/usr/bin/env python


f = open("addresslist.csv", "r")
print(f)
f.close()

```
openでファイルを開き、最後に開いたファイルをクローズします。
クローズする前に受け取ったデータをプリントしています。
今回は同じフォルダ内にcsvファイルを入れていますので、
ファイル名のみで受け取る事が可能です。
（別フォルダのファイルを読む場合は、パスを記載します。）


ファイルを実行してみると

![1.JPG](https://qiita-image-store.s3.amazonaws.com/0/100769/da9e7cb0-24c5-736b-934a-cca45664cd17.jpeg)

無事、addresslist.csvを受け取っている事がわかります。

### 読込むファイル名を都度変えたい
さて、本来の流れから少しそれますが、ここまではプログラム内で
読込むファイル名を固定してaddresslist.csvとしていました。
しかしながら、場合によっては違うファイルを読込みたい場合もあります。

ファイルを実行する際に、コマンドプロンプトで入力したファイル名を取得して利用する方法をご紹介します。

**sysモジュール** インポートします。

```python
# -*- coding: utf-8 -*-
# !/usr/bin/env python
import sys
args = sys.argv
print(args)
```

**sys.argv** はコマンドプロンプトからファイルを実行する際に、python ファイル名　と入力しますよね。
入力する時にpython ファイル名の後に半角スペース区切りで入力したテキストの内容を、リストにして受け取ってくれます。

上記のコードを記載したファイルを実行すると以下のようになります。
![4.JPG](https://qiita-image-store.s3.amazonaws.com/0/100769/d122cf76-6d50-657f-5fbb-852a1b6ec1cb.jpeg)

**python allcode2.py "test"**
と実行した場合は、**['allcode2.py', 'test']**　とかえってきているのがわかります。
**python allcode2.py "test" "DjangoGirls" "elv"**
と実行した場合は、
**['allcode2.py', 'test', 'DjangoGirls', 'elv']**とかえってきているのがわかります。
必ず、リストの最初は実行しているPythonのファイル名になります。

この機能をつかって、ファイルを名を取得し、ファイルを開きます。

```python
# -*- coding: utf-8 -*-
# !/usr/bin/env python

import sys
import csv

args = sys.argv

filename = args[1]

f = open(filename, 'r')

for i in csv.DictReader(f):
    print(i)
```

args という変数にsys.argvでリストを入れています。
上記で説明したように、リストの１つめの要素は実行したファイル名になりますので、リストの２つめの要素を取得します。
（リストについては[こちら](http://qiita.com/sandream/items/e7a215a27c080cf8ac03))
**filename**という変数に args[1]で読込みたいcsvファイルの名称を取得します。

### 例外処理をしよう
さて、ユーザーがファイルを実行する際に、ファイル名を入れ忘れるとファイルが開けず、プログラムはエラーとなります。
そこで、ファイル名を入れ忘れた場合や、存在しないファイル名を指定してしまった時に、プログラムを終了し、わかりやすいエラーを表示するように設定しておきます。
**try:**
    　**実行したい処理**
 **except:**
    　**try配下でためしたプログラムが希望通りに実行できなかった場合の処理**

今回は２つのエラー処理をご紹介します。
（いつか・・別途エラー処理色々の記事も書きたいと思います。）

まずは、ユーザがファイル名を入れ忘れた時に処理です。
**filename = args[1]**と指定した際に、ユーザがファイル名を入力していないと、リストの[1]は存在しないため、エラーとなります。

そこで、エラーとなった場合に、プログラムを終了させ、かつファイル名が入っていない事をユーザに知らせたいと思うので、以下のようにします。

```python
try:
    filename = args[1]
except:
    sys.exit("No file Name!")
```

こうすると、読込むCSVのファイル名を指定せずに実行した場合
![8.JPG](https://qiita-image-store.s3.amazonaws.com/0/100769/f5460669-694e-e0fc-2139-16ccbe80ddff.jpeg)
このように、sys.exit()の()内に指定した文字を表示してくれます。

つぎにユーザがファイル名を入力したとしても、そのファイルが存在しなかった場合、変数filenameにはファイル名が入りますが、
**f = open(filename, 'r')**　で開こうしたした際に、ファイルがないためエラーが発生します。

そこで、以下のように記載します。

```python
try:
    filename = args[1]
    f = open(filename, 'r')
except IOError as e:
    sys.exit("Unable to open file: {}".format(e))
```

**IOEerror**は入力や出力が失敗するときに発生します。例えば、ディスクがいっぱいだったり、入力ファイルが存在しないときに発生するエラーです。
**IOError as e**としているのは、例外が発生したときにその情報を含んだオブジェクトを「e」としてその中の処理(この場合は情報の表示のみ)を実行します。
今回は、エラーメッセージを表示したかったので、設定しています。
エラーの値を利用しない場合は、書く必要はありません。

適当なファイル名を指定して実行してみると、
![9.JPG](https://qiita-image-store.s3.amazonaws.com/0/100769/353bea33-f35f-59d8-a43e-0a21e8bab98c.jpeg)
となります。
Unable to open file:の後が、IOError(eとした部分）のエラーメッセージです。

今回のプログラムでは上記２つのエラー発生の際には、例外処理をほどこしていなくても、プログラムは終了してしますのですが、
例えば、多くのプログラムを書くなかで、この処理は実行できたらしてほしいけど、できなかったらそれはそれで・・いいんです。って時などに
**try:**
    　**実行したい処理**
 **except:**
    　**pass**
  とする事で、エラーが発生した場合には何もしないなどにも使えるので
  覚えておくと良いと思います。

また、エラーメッセージを受け取って、リストにしておいて最後にテキストに書き出すようにすると、一通りプログラムが終了した後に、どこがうまくいかなかったのか確認する事ができ、リカバリする事が出来るので便利です。

### csv.DictReader()を使う
今回は受け取ったデータを１行目をキー。２行目以下は各キーに対するバリューとなる辞書を作成します。

そこで、csvモジュールを使います。
まず　**import csv**でモジュールをインポートします。

```python
# -*- coding: utf-8 -*-
# !/usr/bin/env python
import csv

f = open("addresslist.csv", "r")

for i in csv.DictReader(f):
    print(i)

f.close()
```

（説明のため、上記までにご紹介した例外処理などをいったん省いて表記しています。）

csv.DictReader()は受け取ったｃｓｖデータの１行目をキーとし
次の行からのデータはそのキーのバリューとなるオブジェクトを生成してくれます。

生成したオブジェクトを１行づつ取り出したいので、for文を利用し、
printしています。
上記を実行すると、以下のような結果がとれます。

![2.JPG](https://qiita-image-store.s3.amazonaws.com/0/100769/314969b0-87f9-87a5-e63b-b4a67c629171.jpeg)
＊住所や電話番号はでたらめ情報を入れています

ちなみに、読込んだCSVをリストにしたい場合は
**csv.reader()**を使うとリストになります。

```python
# -*- coding: utf-8 -*-
# !/usr/bin/env python
import csv

f = open("addresslist.csv", "r")

for i in csv.reader(f):
    print(i)

f.close()
```

実行結果
![3.JPG](https://qiita-image-store.s3.amazonaws.com/0/100769/81df9a0a-313e-3116-9ce5-d6feb35a2564.jpeg)

### 書き出ししたいデータ形式に生成する
今回は読込んだCSV(addresslist.csv)を以下の形式にして
別のCSVファイル(allcodelist.csv)として書き出します。
***
住所や電話番号は適当な情報です
***
**addresslist.csv**
![6.JPG](https://qiita-image-store.s3.amazonaws.com/0/100769/fc7bc0d9-c448-9527-0a96-6f248acf73a7.jpeg)

**allcodelist.csv**
![5.JPG](https://qiita-image-store.s3.amazonaws.com/0/100769/7bff588c-4b32-82af-fb7f-e5196ba337e6.jpeg)

### 書き出す形式のリストを作成します。
空のリスト(newcsv)を用意し、その空のリスト(newcsv)に情報を追加していきます。

```python
newcsv = []
top_list = [
        'name',
        'zip code',
        'address',
        'phone',
        'mobile_pyone'
                ]
newcsv.append(top_list)
```
まず、項目の行をtop_listという変数に入れて、書き出しに使うリストnewcsvに追加しています。
リストの追加は　**追加したいリスト名.append(追加するオブジェクト）**と記載します。

項目はできましたので、情報を追加していきます。
csv.DictReader()で受け取った情報を必要な形式に生成してリストに追加していきます。

文字列の生成は色々方法がありますが、今回は**join**をご紹介します。
**つなぎに使う文字を指定.join(つなげたい情報をリストでわたす）**

どういう事かというと・・
![7.JPG](https://qiita-image-store.s3.amazonaws.com/0/100769/0a109dfb-a054-397c-afd2-29cf97eccfae.jpeg)

joinの前に指定した　－　でjoinの後に指定したリストの文字列をつないでいるのがわかります。

文字列の連結は他にもformatや＋を使う方法などありましてそちらの方が一般的かもしれませんが、それは[Pythonでじゃんけんポイっ　初心者向け(回答と解説）](http://qiita.com/sandream/items/01374069f447b7748eba)の文字列の連結でご紹介しておりますので、ご参照ください。
今回は、上記のページでご紹介していなかったので、joinを使わせていただきました。


今回はそれぞれの項目の情報をつなぐようにしていきますので、以下のようにしています。

```python
for i in csv.DictReader(f):
    line = []
    line.append(" ".join((i['lastname'], i['firstname'])))
    line.append(":".join(("郵便番号", i['zip code'])))
    line.append("".join((i['address1'], i['address2'], i['address3'])))
    line.append("：".join(("電話番号", i['phone'])))
    line.append("：".join(("携帯番号", i['mobilephone'])))
    newcsv.append(line)
```
for分の中で、一度一行分のリストを作成したいのでlineという変数に空のリストを生成し、そこに１セル分ずつの情報をいれていきます。
いれおわったら、書き出し用のリスト（newcsv)に追加しています。

### 生成したデータをCSVで書き出す
まずは表現形式を設定します。
**csv.writer(fileオブジェクト,delimiter=デリミタ,lineterminator=改行コード)**
を使います。

fileオブジェクトには、**open(書き出すCSVのファイル名, 書き出し方法**)を指定します。
書き出し方法は、**w**が上書き、**a**は追記となります。

**delimiter=デリミタ**は何で分割するかの指定です。デフォルトは カンマです。CSVはカンマ区切りになりますので、今回は特に指定しません。

**lineterminator=改行コード)**は改行コードです。今回は**/n**を指定します。

```python
writer = csv.writer(open("allcodelist.csv", "w"), lineterminator='\n')
```

表現形式が設定できたら、書き出します。
```python
writer.writerows(newcsv)
```
**writerows(書き出すオブジェクト)** 今回はnewcsvという変数に書き出ししたいデータを入れてありますので、
writerows()の()の中には、newcsvを指定します。

**writerows**は()内に指定したオブジェクトの全てを、 **open(書き出すファイル名, 書き出し方法**)　で指定したファイル名で書き出します。

### 以下、プログラムの全体です。
```python
# -*- coding: utf-8 -*-
# !/usr/bin/env python
import sys
import csv

args = sys.argv
# コマンドプロンプトで入力したファイル名を受け取る
try:
    filename = args[1]
except:
    sys.exit("No file Name!")

# 受け取ったファイル名をつかって該当のCSVを受け取る
try:
    filename = args[1]
    f = open(filename, 'r')
except IOError as e:
    sys.exit("Unable to open file: {}".format(e))

# 書き出すCSVの項目行の生成
newcsv = []
top_list = [
        'name',
        'zip code',
        'address',
        'phone',
        'mobile_pyone'
                ]
newcsv.append(top_list)
for i in csv.DictReader(f):
    line = []
    line.append(" ".join((i['lastname'], i['firstname'])))
    line.append(":".join(("郵便番号", i['zip code'])))
    line.append("".join((i['address1'], i['address2'], i['address3'])))
    line.append("：".join(("電話番号", i['phone'])))
    line.append("：".join(("携帯番号", i['mobilephone'])))
    newcsv.append(line)

# 生成したデータの書き出し
writer = csv.writer(open("allcodelist.csv", "w"), lineterminator='\n')
writer.writerows(newcsv)

f.close()
```

以上、長くなりましたが、ご参考になれば幸いです。
次回はこの内容をもとに、クラスをつくり、その後作ったクラスを継承したクラスを作る！に進みたいと思います。
（記事は現在作成中です。完成したらリンクはります。）