【写経】『みんなのPython 第3版』 Chapter 02 変数と組み込み型
概要
『みんなのPython 第3版』から、「Chapter 02 変数と組み込み型」のサンプルコードを写経する。 少しずつでも、毎日考えながら考えられる時間だけやっていく。
02-01 変数を使う
変数を作る
変数には名前を付ける。
- 品物を分類するために、入れ物に名前を書き込んだタグをつけるようなもの。
- まつもとゆきひろ氏が好きな言葉に「名前重要」を挙げていた。
変数に数値を入れる
>>> a = 1 >>> a 1 >>>
変数を使って計算をする
- 変数による計算①
- 右辺は変数でもよい。
>>> a = a + 1 >>> a 2 >>> a = a + 1 >>> a = a + 1 >>> a 4 >>>
>>> mach = 1225 # 音速 >>> topspeed = 40000 # サターンVの最高速度 >>> topspeed / mach # 音速に換算 32.6530612244898 >>>
- 変数を計算などに使う時は、使う前に変数を定義(オブジェクトを代入)しておく必要がある。
>>> b = b + 1 Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'b' is not defined >>>
変数に文字列を入れる
- 文字列の代入
>>> a = "abc" >>> a 'abc' >>>
変数名の付け方
- 日本語の変数名を使う
- Python2まではアルファベットと数字のみだったが、Python3から日本語を含む色々な文字が使えるようになった。
- が、特別な理由がない限り、変数名は英字と数字だけで作るのが吉。
- Pythonでは、変数名として利用すべき文字に簡単な決まりがある。
>>> ねこ = "にゃー" >>> いぬ = "わん" >>> print(いぬ, ねこ) わん にゃー >>>
(20160824)
02-02 組み込みのデータ型
- データ型
- データを種類や性質によって分類したもの。
- Pythonでは、プログラムでよく利用するデータ型を組み込み型として用意している。
- 組み込み
- Builtinを日本語に翻訳したもの。
- 「特別な宣言や命令なしに利用できる」みたいな意味。
- 組み込み
組み込みのデータ型一覧
- 数値
- 整数型
- 浮動小数点型
- 文字列
- リスト
- 複数の要素を順番に並べて利用するためのデータ型。
- タプル
- 要素の追加や変更ができないリスト。
- ディクショナリ
- キーで要素を管理するリスト。
- その他
- bytes型
- bool型
- set型
02-03 数値を使う
- Pythonは数値を扱うためのデータ型として、整数型と浮動小数点型が別に用意されている。
- 整数型
- 小数点以下の値を含まない。
- 浮動小数点型
- 小数点以下の値を含む。
- 整数型
- 複素数型というのもあるらしいが割愛とのこと。
数値を使った四則演算
>>> 1867 - 1603 264 >>>
(20160825)
- 累乗の例
>>> 2 ** 20 1048576 >>>
四則演算と優先順位
- 計算の優先順位①
- 乗算、除算が優先。
>>> 2 + 3 * 5 17 >>>
- 計算の優先順位②
- 丸括弧がついているところが優先。
>>> (2 + 3) * 5 25 >>>
変数を使った演算と複合演算子
- 変数を計算に使う
- 変数の中に入っている数値を使って計算できる。
>>> length = 110 # サッカー場の長さ(ヤード) >>> length * 0.9144 # メートルに変換 100.584 >>>
- 変数の数値を増やす
>>> a = 1 >>> a = a + 1 >>> a 2 >>>
- 複合演算子の利用例
- 上の例は「+=」を使ったほうが手早く書ける。
- 「*=」「/=」も利用できる。
- 「++」(インクリメント)「--」(デクリメント)は利用できない。
>>> a = 1 >>> a += 1 >>> a 2 >>>
- 複合演算子を試してみる。
- 「/=」で小数点第一位が出てくるのはなんでだったろうか?ドットインストールで習った気がする。
>>> a = 2 >>> a -= 1 >>> a 1 >>> >>> >>> a = 2 >>> a *= 2 >>> a 4 >>> >>> >>> a = 2 >>> a /= 2 >>> a 1.0 >>>
(20160826)
数値演算を使ったプログラム
- MacのACアダプターが復活したので、turtleを試せるようになった。
[python_shakyo 20:13:30 bef]$cat turtle2.py #!/usr/bin/env python # encoding: utf-8 from turtle import * degree = 1 # 角度の初期値 distance = 50 # 距離の初期値 for i in range(40): # 40回繰り返す forward(distance) # distance分進む right(degree) # degree分右に曲がる degree += 2 # 角度を2足す distance -= 1 # 距離から1を引く input() [python_shakyo 20:13:35 bef]$
02-04 文字列を使う
Pythonでは、文字を順番に並べて文字列として扱う。
- 文字列内の文字にはインデックスと呼ばれる0から始まる番号が振られる。
- インデックスを指定することで、文字列の中の特定の文字を取り出すことができる。
文字列はシーケンス型。リストも同様?
文字列を定義する
- 変数に文字列を代入する
- ダブルクオーテーションで囲まれた部分が文字列データを定義している部分(リテラル)。
>>> s = "Spam! Lovely spam!" >>> s 'Spam! Lovely spam!' >>>
文字列リテラルの定義方法
- ダブルクオーテーションを内包する文字列リテラル
- エラーになる。
>>> s = "What do you mean "Urgghh"?" File "<stdin>", line 1 s = "What do you mean "Urgghh"?" ^ SyntaxError: invalid syntax >>>
- シングルクオーテーションを使う
>>> s = 'What do you mean "Urgghh"?' >>> s 'What do you mean "Urgghh"?' >>>
- 「"""」による文字列リテラルの定義
- 3重クオーテーションに囲まれた部分の改行はそのまま変数に格納される。
- シングルクオーテーションが2重になったものがダブルクオーテーションなのに、「"""」が3重クオーテーションなのはおかしい。3重ダブルクオーテーションではないのか。
>>> htmlbody = """<body> ... <h2>Page Title</2> ... <p> ... Page body. ... </p> ... </body> ... """ >>>
- 文字列を表示する
>>> print(htmlbody) <body> <h2>Page Title</2> <p> Page body. </p> </body> >>>
- インタラクティブシェルだったら変数名だけで表示されるんじゃなかったっけ?
- 試してみたら改行コードで表示された。
>>> htmlbody '<body>\n<h2>Page Title</2>\n<p>\nPage body.\n</p>\n</body>\n' >>>
文字列の連結と繰り返し
- 文字列の足し算
- 文字列どうしで足し算すると文字列を連結できる。
- 中身が数字であっても文字列として処理する。
- Pythonの「+」記号は単なる加算だけでなく「オブジェクト同士を繋げる」という意味を持つ。
>>> nstr = "1234" >>> result = nstr + "5678" >>> result '12345678' >>>
- 文字列の掛け算
- 文字列に数字を掛けると文字列の繰り返しになる。
- Pythonの「*」記号は単なる乗算だけでなく「オブジェクト同士を繰り返す」という意味を持つ。
>>> linestr = "-" * 20 >>> linestr '--------------------' >>>
文字列と数値の型変換
- 文字列と数値の足し算
- 型が違うのでエラーになる。
>>> nstr = "1234" >>> nstr + 5678 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: Can't convert 'int' object to str implicitly >>>
文字列を数値に変換する
- int()関数の利用例
- 文字列を数値に変換する。
- int()は小数点のついた文字列を変換できない。
- float()を使う。
>>> nstr = "1234" >>> int(nstr) + 5678 6912 >>>
数値を文字列に変換する
- str()関数の利用例
- 数値を文字列に変換したので、文字列の連結になる。
- int()やfloat()、str()は厳密には関数ではないらしい。
- ずっと先のページがサジェストされていて、クラス(クラスコンストラクタ)とされていた。静かに元のページに戻った。
>>> nstr = "1234" >>> nstr + str(5678) '12345678' >>>
(20160827)
文字列の長さを調べる
- len()関数の使用例
- 文字列の長さを調べる。
- リストやタプルなどのオブジェクトの要素数を調べることもできる。
- 文字列はシーケンス型という括りでリストと同じだから、当然なのか?
>>> word = "floccinaucinihilipilification" >>> len(word) 29 >>> len("オガサワラチビヒョウタンヒゲナガゾウムシ") 20 >>>
文字列の置換や検索を行う
演算子を使った処理
- in演算子を使った検索
- TrueかFalseが返ってくる(bool値)。
>>> address = "香取市木内虫幡上小堀入会地大平" >>> "虫" in address True >>> "町" in address False >>>
メソッドを使った処理
- replace()メソッドを使った置換
- 検索文字列と置換文字列の2つの引数が必要。
>>> address.replace("香取市", "千葉県香取市") '千葉県香取市木内虫幡上小堀入会地大平' >>>
- 数(変数の誤記?)の中身を確認する
- replace()しても元の変数の中身は変わらない。
>>> address '香取市木内虫幡上小堀入会地大平' >>>
- replace()メソッドの戻り値を変数に代入する
- replace()した後の値をそのまま使いたい場合は、変数に代入すればよい。
>>> address = address.replace("香取市", "千葉県香取市") >>> address '千葉県香取市木内虫幡上小堀入会地大平' >>>
インデックスを使って要素を取り出す
- 文字列のインデックスを使う
- インデックスは0始まり。
- 返ってくるのは1文字の文字列。
>>> digits[2] '3' >>>
- ord()関数とchr()関数
- ord()は1文字の文字列を文字コード相当の数値に変換する。
- chr()はその逆。
- 何に使うんだこれ。
>>> ord(digits[2]) 51 >>> chr(52) '4' >>>
- 文字列を置き換えようとするとエラーになる
- 文字列そのものを書き換えることはできない。
- 書き換えをするならreplace()メソッドを使うなどする。
>>> digits[2] = "4" Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'str' object does not support item assignment >>>
02-05 リストを使う
- どんなオブジェクトも入れられる。
- リストそのものでも入れられる。
- スライス?を使うと複数の要素に対して操作ができる。
- 文字列型同様シーケンス型に分類される。
- シーケンス型をループ処理で利用する。
- シーケンス型を使いこなせるとループをスマートに処理できるようになるらしい。
リストを定義する
- リストの定義
- 角括弧で囲み、カンマで要素を区切る。
>>> a = [1, 2, 3, 4, 5] >>> a [1, 2, 3, 4, 5] >>>
インデックスを指定して要素を取り出す
- インデックス利用
- マイナスの整数を指定すると、最後から数えた要素を取り出せる。
- -1を指定すれば、(リストの長さに関わらず)最後の要素を取り出せる。すごい役に立ちそう。
>>> a[2] 3 >>> a[-1] 5 >>>
- インデックスエラー
>>> a[100] Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: list index out of range >>>
スライスを利用して要素を取り出す
- スライスによるリストの取り出し
- リスト内の複数の要素をいっぺんに取り出すことができる。
- [A:B]で、インデックスがA以上B「未満」の範囲の要素を取り出せる。
- なぜB「以下」にしなかったのか……。
- 返ってくるのはリスト型オブジェクト。
- リスト内の複数の要素をいっぺんに取り出すことができる。
>>> a[1:3] [2, 3] >>> a[3:4] [4] >>>
- スライスのいろいろな指定法
- コロンの左側を省略すると「0」(=要素の最初から)を指定したことになる。
- コロンの右側を省略すると、要素の最後までを指定したことになる。
- つまり、(テキストには書いてないけど)「-1」を指定したのと同じ?
- B「未満」なので、そうはならない。
>>> a[2:] [3, 4, 5] >>> a[:3] [1, 2, 3] >>> a[2:100] [3, 4, 5] # 右側に-1を指定したが、a[2:]と同じ結果にはならなかった # -1「未満」の要素が取り出されるから、インデックスが-2の4が取り出された、という解釈でいいのだろうか? >>> a[2:-1] [3, 4] >>>
リストを使った足し算、掛け算
- リストの足し算
- 2つのリストを足すと、リストを連結することができる。
>>> b = a + [100, 101, 102] >>> b [1, 2, 3, 4, 5, 100, 101, 102] >>>
- リストに要素を追加
- 失敗。リストに加える時も型を合わせなければならない。
- Pythonは型に厳しい。
>>> c = a + 100 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: can only concatenate list (not "int") to list >>>
- 足し算でリストの末尾に追加
>>> c = a + [100] >>> c [1, 2, 3, 4, 5, 100] >>>
- リストの掛け算
- 繰り返しになる。
>>> a = [1, 2, 3] * 3 >>> a [1, 2, 3, 1, 2, 3, 1, 2, 3] >>>
要素の置き換え、削除
- リストの要素を置き換える
- インデックスで要素を指定し、要素を代入する。
>>> a = [1, 2, 3, 4, 5] >>> a[1] = "二" >>> a [1, '二', 3, 4, 5] >>>
- 要素の削除
- del文を使う。
- 関数、文、メソッドがごっちゃごちゃになりそう。
>>> a = [1, 2, 3, 4, 5] >>> del a[2] >>> a [1, 2, 4, 5] >>>
(20160628)
リスト要素の検索
- リストの要素の検索
```
names = ['Gary', 'Chick', 'Pat', 'Roy', 'Dave'] "Gary" in names True
- 何番目かを調べる - index()メソッドを使う。 - index()メソッドの場合、リストに存在しない要素を引数として渡すとエラーになる。 - 要素の有無を調べるならin演算子を使うのが得策(要素がなくてもFalseが返ってくるから)。 ``` >>> names.index('Chick') 1 >>> names.index('Hiromi') Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: 'Hiromi' is not in list >>> ``` ## リストの最大値、最小値 - リストの最大値と最小値を求める - それぞれmax()関数とmin()関数を使う。
oilsupply = [271220, 259429, 259705, 262472] max(oilsupply) 271220 min(oilsupply) 259429
- 文字列を含むリストの場合 - lを1と勘違いしてリストを作ろうとしたらエラーが出た。 - それは余談で、文字列の場合は数値の時とは違う結果が出るという話。
1 = ['1', '2', '3', '10'] File "
", line 1 SyntaxError: can't assign to literal l = ['1', '2', '3', '10'] max(l) '3'
リストのソートと順序の反転
- 小さい順に並べ替える
- sort()メソッドを使うと、数値を小さい順に並べ替える。
- オブジェクト自体を書き換え、結果は返さない。
- replace()メソッドのように、変数に代入し直す必要はない。
- なぜこのような違いが生まれるのか?
- replace()メソッドのように、変数に代入し直す必要はない。
>>> gdp = [51317, 50097, 49720, 50125] >>> gdp.sort() >>> gdp [49720, 50097, 50125, 51317] >>>
- 逆順に並び替える
- reverse()メソッドを使う。
- これもオブジェクト自体が書き換わる。
>>> gdp.reverse() >>> gdp [51317, 50125, 50097, 49720] >>>
リストで使用できる他のメソッド
- append()メソッド
- リストの末尾に要素を追加する。
- リストの中にリストを入れることもできる。
>>> a = [1, 2, 3, 4, 5] >>> a.append(100) >>> a [1, 2, 3, 4, 5, 100] >>> a.append([200, 300, 400]) >>> a [1, 2, 3, 4, 5, 100, [200, 300, 400]] >>>
- extend()メソッド
- (さっきの例のようにリストを要素としてリストに入れるのではなく)引数のリスト内の要素を分割して、要素として格納できる。
>>> a = [1, 2, 3, 4, 5] >>> a.extend([200, 300, 400]) >>> a [1, 2, 3, 4, 5, 200, 300, 400] >>>
- turtle3.py
- iは0から39の範囲で変化する。
- 0 & 4 = 0、1 % 4 = 1、2 % 4 = 2……と値が変化していき、それがdegreeに代入されるcurveのインデックスになる。
- 0に対して除算はできないと習ったけど、Python的には大丈夫らしい。
(py3) [python_shakyo 22:40:21 bef]$ cat turtle3.py #!/usr/bin/env python # encoding: utf-8 from turtle import * # 角度のリストを登録する curve = [10, 160, 10,20] speed("fastest") for i in range(40): # 40回繰り返す forward(100) # 100進む degree = curve[i % len(curve)] right(degree) # リストに従って曲がる input() # 0 % 4の答えとは >>> 0 % 4 0 >>>
多次元配列をリストで表現する
- リストのリストを定義する
- 多次元配列でオセロの盤面を表現する。
>>> board = [[0, 0, 0, 0, 0, 0, 0, 0], ... [0, 0, 0, 0, 0, 0, 0, 0], ... [0, 0, 0, 0, 0, 0, 0, 0], ... [0, 0, 0, 1, 2, 0, 0, 0], ... [0, 0, 0, 2, 1, 0, 0, 0], ... [0, 0, 0, 0, 0, 0, 0, 0], ... [0, 0, 0, 0, 0, 0, 0, 0], ... [0, 0, 0, 0, 0, 0, 0, 0]] >>> board [[0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 2, 0, 0, 0], [0, 0, 0, 2, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0]] >>>
- リストのリストの要素の指定
- 最初のインデックスでboardの要素を指定し、2つ目のインデックスで要素となっているリストの要素を指定している。
- ややこしい。プログラムとはこんなことをしなければならないのか。
>>> board[3][4] 2 >>>
- リストのリストに値を代入する
- 要素の指定ができれば、代入も同じようにできる。
>>> board[3][2] = 2 >>> board[3][3] = 2 >>> board[3] [0, 0, 2, 2, 2, 0, 0, 0] >>>
(20160829)
02-06 ディクショナリ(辞書)を使う
- インデックスの代わりにキーで要素を管理するリスト。
- 「名前」と「住所」などのように見出し語と対応する要素をひも付けて管理するのに便利。
ディクショナリを定義する
- ディクショナリを定義する
- 波括弧で囲んで、キーと対応する要素をコロンを挟んで並べる。
- えげつない文字化けした。明日対応する。
>>> d = {"100-0001":"東京都千代田区", "100-0002":"東京都千代田区皇居外苑"} >>> d {'100-0002': '\xe6\x9d\xb1\xe4\xba\xac\xe9\x83\xbd\xe5\x8d\x83\xe4\xbb\xa3\xe7\x94\xb0\xe5\x8c\xba\xe7\x9a\x87\xe5\xb1\x85\xe5\xa4\x96\xe8\x8b\x91', '100-0001': '\xe6\x9d\xb1\xe4\xba\xac\xe9\x83\xbd\xe5\x8d\x83\xe4\xbb\xa3\xe7\x94\xb0\xe5\x8c\xba'} >>>
(20160831)
- やっぱり単に文字コードの問題だった。
- ディクショナリには並び順という概念がないらしく、定義した時と順番が変わってても驚かないこと。
>>> d = {"100-0001":"東京都千代田区", "100-0002":"東京都千代田区皇居外苑"} >>> d {'100-0002': '東京都千代田区皇居外苑', '100-0001': '東京都千代田区'} >>>
キーを使って要素を取り出す
- 要素の取り出しと代入
- 取り出すときは波括弧じゃなくてリストと同じ角括弧を使う。謎。
- キーを指定して代入すると、ディクショナリの要素を変更できる。
>>> d = {"100-0001":"東京都千代田区", "100-0002":"東京都千代田区皇居外苑"} >>> d['100-0001'] '東京都千代田区' >>> # 波括弧はダメ >>> d{'100-0001'} File "<stdin>", line 1 d{'100-0001'} ^ SyntaxError: invalid syntax >>> >>> d['100-0001'] = "東京都千代田区千代田" >>> d {'100-0002': '東京都千代田区皇居外苑', '100-0001': '東京都千代田区千代田'} >>>
ディクショナリに新しいキーと要素を追加する
- キーを追加する
- やはり角括弧。
>>> d['100-0003'] = "東京都 千代田区 一ツ橋(1丁目)" >>> d {'100-0002': '東京都千代田区皇居外苑', '100-0003': '東京都 千代田区 一ツ橋(1丁目)', '100-0001': '東京都千代田区千代田'} >>>
- 存在しないキーを指定する
- そんなキーはありませんよ、とエラーが返ってくる。
>>> d['123-0123'] Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: '123-0123' >>>
キーを使って要素を削除する
- 要素の削除
- リストと同じくdel文を使う。
>>> del d['100-0001'] >>> d {'100-0002': '東京都千代田区皇居外苑', '100-0003': '東京都 千代田区 一ツ橋(1丁目)'} >>>
キーの一覧と確認
- ディクショナリの定義
- 例に漏れずディクショナリもオブジェクトなので、独自のメソッドを持っている。
- ディクショナリのメソッドを使うと、ディクショナリに登録されているキーや値の情報を取り出すことができる。
>>> rssitem = {"title":"Python3を勉強中", "link":"http://host.to/blog/entry", "dc:date":"2012-05-16T13:24:04Z"} >>> rssitem = {"title":"Python3を勉強中", ... "link":"http://host.to/blog/entry", ... "dc:date":"2012-05-16T13:24:04Z"} >>> rssitem {'link': 'http://host.to/blog/entry', 'dc:date': '2012-05-16T13:24:04Z', 'title': 'Python3を勉強中'} >>>
- keys()メソッドの実行
- ディクショナリに登録されているキーの一覧を得ることができる。
- 返すのはリスト型のオブジェクトではなく、メモリビューと呼ばれるものらしい。伏線がたくさん張られている。
>>> rssitem.keys() dict_keys(['link', 'dc:date', 'title']) >>>
- 特定のキーを探す
- in演算子を使う。
>>> "link" in rssitem True >>> "dc:creator" in rssitem False >>> # 要素は検索対象じゃない >>> 'http://host.to/blog/entry' in rssitem False >>>
(20160901)
02-07 タプルを使う
- リストに似ているが、要素を書き換えることはできない。
タプルを定義する
- タプルの定義
- 丸括弧で要素を囲む。
>>> t = (1, 2, 3, 4, 5) >>> t (1, 2, 3, 4, 5) >>>
タプルを利用する
- タプルから要素を取り出す
- リストと同じく、インデックスで指定すれば良い。
- スライスも同様に使える。
- リスト、ディクショナリ、タプルそれぞれの代入時の括弧の形は違うけれども、インデックスを指定するときは常に角括弧、と覚えることにする。
>>> t[1] 2 >>> t[2:4] (3, 4) >>>
- 書き換えはできない
- 文字列と同様。
>>> t[4] = "Five" Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'tuple' object does not support item assignment >>>
- タプルの足し算
- タプル同士の連結はできる。
>>> t2 = t + (100, 200, 300) >>> t2 (1, 2, 3, 4, 5, 100, 200, 300) >>>
タプルの利点
- メモリの使用効率が良くなる。
- 扱う項目数があらかじめ決まっているから。
- ディクショナリのキーとして利用できる。
- リストはできないが、タプルは内容が変わらないため。
02-08 組み込み型の分類とまとめ
コレクション型
- 複数の要素を持つことができるデータ型。
- シーケンス型
- 複数の要素を順番に並べてデータを管理するデータ型。
- 文字列、リスト、タプル
- 複数の要素を順番に並べてデータを管理するデータ型。
- マップ型
- キーと値のペアで要素を管理するデータ型。
- ディクショナリ
- キーと値のペアで要素を管理するデータ型。
- シーケンス型
「変更可能」と「変更不可能」
- 変更可能はmutable、変更不可能はImmutableを訳した言葉。イミュータブル、よく聞く。
- 変更可能な組み込み型
- リスト、ディクショナリ
- 変更不可能な組み込み型
- 文字列、タプル
- 変更可能な組み込み型
組み込み型相互の変換
list()関数
- 他のシーケンス型をリストに変換できる。
tuple()関数
- 他のシーケンス型をタプルに変換できる。
str()関数
- オブジェクトをふさわしい表記の文字列に変換する。
型変換の例
>>> t = (1, 2, 3, 4, 5) >>> t (1, 2, 3, 4, 5) >>> a = list(t) >>> a [1, 2, 3, 4, 5] >>> t2 = tuple(a) >>> t2 (1, 2, 3, 4, 5) >>> # str()関数 >>> str(t2) '(1, 2, 3, 4, 5)' >>>
(20160904)
メモ
- 結構時間がかかった。写経は朝やると言いつつ、結局夜やることがほとんどだった。朝しんどい。(20160904)