Pythonで入出力（Python学習メモ⑤）

## 出力フォーマット 
ポイント

* 値を書きだす方法（代表的なもの）
    * 対話モードで式だけ入力
    * print()
    * write() ※標準出力はsys.stdoutとして参照できる
* 出力のフォーマット方法
    * 文字列スライシングや連結操作を利用
    * str.formatメソッドを利用
    * stringのTemplateクラスを利用
* 値を文字列に変換する方法
    * repr()関数
    * str()関数
* str()は人間に読みやすい表現で返す
* repr()はインタープリタが読める表現を生成

```python
s = 'Hello, world.'
print(str(s))
# Hello, world.
print(repr(s))
# 'Hello, world.'
print(str(1/7))
# 0.14285714285714285

x = 10 * 3.25
y = 200 * 200
s = 'The value of x is ' + repr(x) + ', and y is ' + repr(y) + '...'
print(s)
# The value of x is 32.5, and y is 40000...

# 文字列のrepr()は文字列クォートとバックスラッシュもそのまま返す
hello = 'hello, world\n'
hellos = repr(hello)
print(hellos)
# 'hello, world\n'

# あらゆるPythonオブジェクトがrepr()で変換できる
print(repr((x, y, ('spam', 'eggs'))))
# (32.5, 40000, ('spam', 'eggs'))

```

* `str.rjust()`を使用して指定の幅に右揃えできる
* 類似のメソッドで`ljust()`, `center()`がある


```python:rjust()を使った右揃え
for x in range(1, 11):
    print(repr(x).rjust(2), repr(x*x).rjust(3), end=' ')
    print(repr(x*x*x).rjust(4))

# 出力
#  1   1    1
#  2   4    8
#  3   9   27
#  4  16   64
#  5  25  125
#  6  36  216
#  7  49  343
#  8  64  512
#  9  81  729
# 10 100 1000
```

```python:formatを使った右揃え

for x in range(1, 11):
    print('{0:2d} {1:3d} {2:4d}'.format(x, x*x, x*x*x))

# 出力
#  1   1    1
#  2   4    8
#  3   9   27
#  4  16   64
#  5  25  125
#  6  36  216
#  7  49  343
#  8  64  512
#  9  81  729
# 10 100 1000

```

* `zfill()`は文字列の左側をゼロパディングする


```python
print('12'.zfill(5))
# 00012

print('-3.14'.zfill(7))
# -003.14

print('3.14159265359'.zfill(5))
# 3.14159265359

```

* `str.format()`は文字列内の`{}`と引数の値を置き換える
* `{1}`のように置換する引数の番号で指定可能
* `{arg}`のようにキーワード引数を設定する方法もある
* 混ぜて使う方法もある

```python:フォーマットいろいろ
# format で {} を利用
print('Happy birth day {} !, You are {} years old now !'.format('Kawauso', '5'))
# Happy birth day Kawauso !, You are 5 years old now !

# 引数の番号指定
print('Happy birth day {0} !, You are {1} years old now !'.format('Kawauso', '5'))
# Happy birth day Kawauso !, You are 5 years old now !

# キーワード引数指定
print('Happy birth day {name} !, You are {year} years old now !'.format(name='Kawauso', year='5'))
# Happy birth day Kawauso !, You are 5 years old now !

# 番号とキーワード引数の混在
print('Happy birth day {0} !, You are {year} years old now !'.format('Kawauso', year='5'))
# Happy birth day Kawauso !, You are 5 years old now !

# float型表記
print('Happy birth day {name} !, You are {year:3f} now !'.format(name='Kawauso', year=5))
# Happy birth day Kawauso !, You are 5.000000 now !

# rを使うとrepr()が適用される
print('Happy birth day Kawauso !, You are {!r} now !'.format(5.12345678))
# Happy birth day Kawauso !, You are 5.12345678 now !

# 小数点以下3桁で表記
import math
print('円周率πはおよそ{0:.3f}である'.format(math.pi))
# 円周率πはおよそ3.142である

# %を使った指定方法
print('円周率πはおよそ%5.3fである' % math.pi)
# 円周率πはおよそ3.142である

# :の後に整数を渡すとフィールドの文字数の最小幅を指定できる
table = {'kawauso': 100, 'mando': 200, 'banjo': 300}
for name, num in table.items():
    print('{0:10} ==> {1:10d}'.format(name, num))

# kawauso    ==>        100
# mando      ==>        200
# banjo      ==>        300

# dictを渡して[]でアクセスすると名前で指定できて便利
print('kawauso: {0[kawauso]:d}; mando: {0[mando]:d}; ' 
    'banjo: {0[banjo]}'.format(table))
# kawauso: 100; mando: 200; banjo: 300

# **表記を使ってキーワード引数として渡しても同じことができる
print('kawauso: {kawauso:d}; mando: {mando:d}; ' 
    'banjo: {banjo}'.format(**table))
# kawauso: 100; mando: 200; banjo: 300

```

## ファイルの読み書き

### open()
```python
f = open('file', 'w')
```

* 第1引数は文字列でファイル名
* 第2引数はモード
    * r: 読み込み専用
    * w: 書き出し専用
    * a: ファイル末尾に追記
    * r+: 読み書き両用
    * 指定なし: rになる
    * b: バイナリモードで開く
* 通常はテキストモードで開かれる
* テキストモードではプラットフォーム依存の行末文字は`\n`に変換される
* 書き込みでは`\n`からプラットフォーム依存の行末文字に戻される

### ファイルオブジェクトのメソッド

このテキストファイルに対して操作していく

```text:workfile
1行目
2行目
3行目
```

#### f.read()

* 現在位置からファイルの終わりまで読み込む

```python
f = open('workfile', 'r')
print(f.read())
# 出力
# 1行目
# 2行目
# 3行目
f.close()
```

#### f.readline()

* 1行読み込んで次の行へ

```python
print(f.readline())
print(f.readline())

# 出力
# 1行目
#
# 2行目
```

* ファイルの各行に対してforループすることもできる

```python
for line in f:
    print(line, end='')

# 出力
# 1行目
#
# 2行目
#
# 3行目
    
# f.write('4行目')
# print(f.read())
```

#### f.readlines()
* 各行を配列に格納

```python
print(f.readlines())

# 出力
# ['1行目\n', '2行目\n', '3行目']
```

#### f.write()
* 文字列を書き込み、下記もまれたキャラクタの数を返す

```python
print(f.write('4行目'))

# 出力
# 3
```
#### f.tell()
* 現在位置(ファイル先頭からのバイト数)を返す
* バイナリモードならそのままの意味だが、テキストモードではよくわからない数になる

#### f.seek(オフセット, 起点)
* 現在位置を変えたいときに使う
* オフセットは起点からのバイト数を指定(マイナス値も指定可能)
* 起点は0: ファイルの先頭、1: 現在位置, 2: ファイルの末尾から指定

```python
f = open('workfile', 'rb+')
print(f.write(b'0123456789abscef'))
# 16
print(f.seek(5))
# 5
print(f.read(1))
# b'5'
print(f.seek(-3, 2))
# 16
print(f.read(1))
# b's'
```

#### f.close()
* ファイルへの操作が終わったらcloseをコールしてシステムリソースを開放すること

### ファイルを扱うときはwithを使おう
* 一連の操作から抜けるときにファイルが正しく閉じられるので、closeし忘れの防止になる
* try-finalyブロック書くより簡潔

```python
with open('workfile', 'r') as f:
    read_data = f.read()

print(f.closed)
# True
```

### オブジェクトをjson文字列化してファイルに保存
ポイント

* jsonパッケージを利用してシリアライズ、デシリアライズ、保存

```python
import json
x = [1, 'kawasuo', 'list']

print(json.dumps(x))
# [1, "kawasuo", "list"]

with open('sample.json', 'w') as f:
    # sample.jsonへ書き込み
    json.dump(x, f)

with open('sample.json', 'r') as f:
    # sample.jsonから読み込み
    print(json.load(f))
    # [1, "kawasuo", "list"]
```