100日後にエンジニアになるキミ - 26日目 - Python - Python言語の基礎3


前回はこちら

[100日後にエンジニアになるキミ - 25日目 - Python - Python言語の基礎2](https://qiita.com/otupy/items/f031846d736fe342de71)


## 文字列

[![表示されなかったらすみません](https://img.youtube.com/vi/tq_Zd9H65uE/0.jpg)](https://youtu.be/tq_Zd9H65uE)

pythonのデータ型の中でも文字列型は一番よく使うデータ型です。

なので、文字列型の取り扱い方を詳しく見ていきましょう。

**文字列型について**

文字列型にする場合は
`'`シングルクォートや`"`ダブルクォートで囲みます。
変数に格納する際も同様です。

```
st = 'abcde'
print(st)
print(type(st))
```
abcde
`<class 'str'>`


**シングルクォートやダブルクォートの使い分け**

`"..."` の中では `'` を、`'...'` の中では `"` を使うことができます。
`"..."` の中で " を、`'...'` の中で ' を使用するには、
`\`バックスラッシュ (Windows の環境では `¥`)を用いて引用符をエスケープ(無効化)します。

```
# \ バックスラッシュを用いるとその後に続く引用符が無効になり、表示させることができる。
st = "We can use \" in the string."
print(st)

st = 'We can use \' in the string.'
print(st)
```
We can use " in the string.
We can use ' in the string.


**エスケープ文字**

特殊な文字列を打ち込む場合には、このエスケープ文字を使用します。


macは `\` バックスラッシュ
windowsは `¥` 円マーク

`\n`　とすると改行コード、`\t`と打ち込むとタブを表現できる。

```
# 改行コード
print('aaaa \n bbbb')

# タブ
print('cccc \t dddd')
```
aaaa
bbbb
cccc dddd

改行はエンターキーだが、打ち込むことはできないので
改行を含ませたい場合はエスケープ文字を使って表現できます。

このようにエスケープ文字を使って表現する特定の文字のことを
`エスケープシーケンス`と言います。

他にもいくつかエスケープシーケンスがありますが、
余り使わないかもしれません。

**三重クォート**

三重クォート `"""..."""` や `'''...'''` は、
複数行にまたがった文字列を記述することができます。

三重クォートはしばしば、複数行のコメントとして利用されることがあります。

```
mail_text = '''
林様

お世話になっております。木森です

本日はウェルカムトゥーザジャングルをお届けいたします。
'''
print(mail_text)
```
林様

お世話になっております。木森です

本日はウェルカムトゥーザジャングルをお届けいたします。

メールの差し込み文章を作るときなどによく使われる手法です。
文章をあらかじめ変数に用意しておいて
その一部を取り替えると、いろいろな人向けの本文が作成できます。

**文字列関数について**
Pythonでは文字列を操作するいろいろな関数が備わっています。

その中からよく使うものをご紹介します。

`replace` : 文字列を置換する
`置換対象文字列.replace('置換前文字列','置換後文字列')`

```
aaa = 'abcdefg'
print(aaa)
# replaceでdef を zzzz　に変換
print(aaa.replace('def','zzzz'))
```
abcdefg
abczzzzg

`in` , `startswith` , `endswith`
対象の文字列に対して検索文字列を含むかどうかの判定をして真偽値を返します。

`検索文字列 in 対象の文字列` ：文字列を含むかどうかの判定する
`対象の文字列.startswith(検索文字列)`： 始まりの文字列かどうかを判定する
`対象の文字列.endswith(検索文字列)` ： 終端の文字列かどうかを判定する

```
apple = 'apple'
# apple　に pp　が含まれるかどうかを判定する
print('pp' in apple)

# apple　がapp　で始まるかどうかを判定する
print(apple.startswith('app'))

# apple　が　le　で終わるかどうかを判定する
print(apple.endswith('le'))
```
True
True
True



`split` , `rsplit` , `splitlines` :
文字列をリストに変換

`文字列.split(区切り文字)` :
指定したセパレーターをもとに文字列を区切り, リストを返す

`文字列.rsplit(区切り文字 , 区切り個数)` :
区切りはじめる方向がsplit()と逆から引数指定分までを返す

`文字列.splitlines()` :
改行ごとに文字列を区切り, リストを返す
リスト型については詳細は次項で説明する。

```
# , 区切りでリスト型にする
print('aaaa,bbb,ccc'.split(','))

# 区切りはじめる方向がsplit()と逆から引数指定分までを返す
print('aaaa,bbb,ccc'.rsplit(',',1)) 

# 改行ごとに文字列を区切り, リストを返す
print('aaaa\nbb\ncc'.splitlines())
```
['aaaa', 'bbb', 'ccc']
['aaaa,bbb', 'ccc']
['aaaa', 'bb', 'cc']

`join()` :
かっこの中のリスト型の文字列を連結する

`'区切り文字'.join([文字,文字])`

```
aaa = ','.join(['a','b','c'])
print(aaa)
```
a,b,c


`count()` :
文字の個数をカウントする

`検索対象文字列.count(カウントしたい文字列)`
見つかれば個数、見つからない場合は0を返します。

```
aaa = '平平平平'.count('平')
print(aaa)

aaa = '平平平平'.count('米')
print(aaa)
```
4
0


ここから下は使う頻度は少ないものですが
文字列関数として備わっているものです。


`find` , `rfind` , `index` , `rindex` :
文字列の位置の判定を行う

`対象の文字列.find(検索文字列)` ：
検索文字列を探し, あった場合は, 最小のインデックスを返す
なければ-1を返す

`対象の文字列.rfind(検索文字列))` ：
検索文字列を探し, あった場合は, 最大のインデックスを返す
なければ-1を返す

`対象の文字列.index(検索文字列)` ：
検索文字列を探し, あった場合は, 最小のインデックスを返す
なければエラーを返す

`対象の文字列.rindex(検索文字列)` ：
検索文字列を探し, あった場合は, 最大のインデックスを返す
なければエラーを返す

```
# appleから p を探し, あった場合は, 最小のインデックスを返す. なければ-1を返す
print('apple'.find('p'))  

# appleから p を探し, あった場合は, 最大のインデックスを返す. なければ-1を返す
print('apple'.rfind('p')) 

# pen pine apple pen から e を探し, あった場合は, 最小のインデックスを返す
# なければエラーを返す
print('pen pine apple pen'.index('e'))  

# pen pine apple pen からe を探し, あった場合は, 最大のインデックスを返す
# なければエラーを返す
print('pen pine apple pen'.rindex('e')) 
```
1
2
1
16


`isalnum` , `isalpha` , `isdigit` , `islower` , `isspace` , `istitle` :
文字列の構成要素の判定

`文字列.isalnum()` :
文字がすべて英数文字かどうかの判定

`文字列.isalpha()` :
文字がすべて英字かどうかの判定

`文字列.isdigit()` :
文字がすべて数字かどうかの判定

`文字列.islower()` :
大小文字の区別がある文字がすべて小文字かどうかの判定

`文字列.isspace()` :
文字がすべて空白かどうかの判定

`文字列.istitle()` :
文字列がタイトルケース(先頭が大文字)かどうかの判定

```
# 文字列が英数字だけかどうかを判定する
print('az189898ssss'.encode('utf-8').isalnum()) 

# 文字列が全て英字だけかを判定する
print('aaaaAAAZZZzz'.encode('utf-8').isalpha()) 

# 文字列が数字だけかを判定する
print('123112399876'.encode('utf-8').isdigit()) 

# 小文字だけかどうかを判定する
print('abcdefghijkl'.encode('utf-8').islower()) 

# 文字が空白かどうかを判定する
print('            '.encode('utf-8').isspace()) 

# 文字列がタイトルケース(先頭が大文字)かどうかの判定
print('Apple Zedd  '.encode('utf-8').istitle()) 
```
True
True
True
True
True
True


`capitalize` , swapcase` , `title` , `lower` , `upper` :
大文字, 小文字の変換

`文字列.capitalize()` :
最初の文字のみを大文字にする

`文字列.swapcase()` :
大文字を小文字に, 小文字を大文字に変換する

`文字列.title()` :
文字列をタイトルケース(先頭が大文字)にする

`文字列.lower()` :
文字をすべて小文字に変換する

`文字列.upper()` :
文字をすべて大文字に変換する

```
# 最初の文字のみを大文字にする
print('az189898ssss'.capitalize()) 

# 大文字を小文字に, 小文字を大文字に変換する
print('az189898SSSS'.swapcase())   

# 文字列をタイトルケース(先頭が大文字)にする
print('az189898ssss'.title())      

# 文字をすべて小文字に変換する
print('Za189898SsSs'.lower())      

# 文字をすべて大文字に変換する
print('az189898ssss'.upper()) 
```
Az189898ssss
AZ189898ssss
Az189898Ssss
za189898ssss
AZ189898SSSS

## 文字列のフォーマット

[![表示されなかったらすみません](https://img.youtube.com/vi/dPHW6BrNUy8/0.jpg)](https://youtu.be/dPHW6BrNUy8)

前の項では文字列の関数について取り扱いました。
その中でも文字列の`フォーマット`に関する部分は覚えることが多いので
詳しくやっていきたいと思います。

`フォーマット`とは文字列の出力を制御すること

文字列の`フォーマット`を行う方法としては3つ方法があります。

`1つ目 文字列に特定のフォーマット文字をさしこんでフォーマットする。`
`2つ目 format関数を使う。`
`3つ目 文字列型のformat関数を使う。`

2,3つ目は`format`用の関数を使い、少しだけ書き方が違うだけで
ほぼほぼ一緒です。

**format文字でフォーマットする方法**

`'文字列 %差し込みするデータがに対応する記号' % (変数)`

`%s` : 文字列型
`%d` : 整数型
`%f` : 小数点型
`%x` : 16進法表記
`%o` : 8進法表記
`%%%d` : %を付けたい場合

```
errmsg = "Can't open file"
errcode = 19042
# 文字列に変数の結果を差し込む %s , %d
msg = "ERROR: %s (%d)" % (errmsg, errcode)
print(msg) 
```
ERROR: Can't open file (19042)

上記の例だと通常の`print`関数では
文字列型のデータと数値のデータを一緒には取り扱えませんが
フォーマット文字を使った差し込みであればデータの型が違っても扱うことができます。

`%s` の部分に文字列型
`%d` の部分に整数型のデータを差し込むことができる。

```
# 文字列型
print ("%s" % "ABC")
# 整数型
print ("%d" % 123)
# 小数点型
print ("%f" % 1.23)
# 16進法
print ("%x" % 255)
# 8進法
print ("%o" % 255)
# %を表示したい場合
print ("%%%d" % 80)
```
ABC
123
1.230000
ff
377
%80

フォーマットで便利な点としては、% に続く数値で
文字幅や桁数を指定することができます。

```
#=> |  ABC| : 右寄せ5文字分
print ("|%5s|"   % 'ABC')      

#=> |ABC  | : 左寄せ5文字分
print ("|%-5s|"  % 'ABC')      

#=> |  123| : 右寄せ5桁
print ("|%5d|"   % 123)     

#=> |123  | : 左寄せ5桁
print ("|%-5d|"  % 123)        

#=> | +123| : ±符号付き
print ("|%+5d|"  % 123)        

#=> | 1.23| : 全体桁数.少数点以下の桁数
print ("|%5.2f|" % 1.23)       

#=> |00123| : 0埋め
print ("|%05d|"  % 123) 
```
| ABC|
|ABC |
| 123|
|123 |
| +123|
| 1.23|
|00123|

**format関数を使う方法**

`format(差し込むデータ , 差し込む先の文字列)`

`差し込む先の文字列.format(差し込むデータ)`

個人的には　`文字列.format()`の方が使いやすので
こちらをメインで説明します。

差し込む先の文字列には `{}` 波カッコ　を付けて
その中に文字を差し込みします。

```
aaa = 'このあとに文字を差し込む {}  差し込んだ'.format('さしこ')
print(aaa)
```
このあとに文字を差し込む さしこ 差し込んだ

`{}`の部分に文字を差し込むことができます。

複数個の文字の差し込みに対応する場合はインデックスを用います。
`{}` 波カッコ内のインデックス番号が、format関数に入れる順番に対応します。

```
# １番目は0、２番目は１に、3番目のデータが2のところに入る。
print('{0}-{1}-{2}'.format('100', '二百', 300))
```
100-二百-300

`{0}`には初めのデータ,`{1}`には2個目のデータが差し込まれます。

`{}`波カッコ内に任意の名前を指定し
キーワード引数として入力することも可能です。

```
# それぞれの名称に対応する文字が入る
print('{year}年{month}月{day}日'.format(year=2018, month=1, day=11))
```
2018年1月11日

`{year}`には引数で指定した`year=`の値が差し込まれます。

**左寄せ、中央寄せ、右寄せ**

`<` `^` `>`で左寄せ、中央寄せ、右寄せができます。
全体の文字数を数値で指定し埋める文字を指定することもできます。
省略するとスペースになり、一文字であれば全角でもOKです。

`{:寄せ記号 桁数}.format(数値など)`

```
print('left  : {:<10}'.format(100))   # 左寄せ
print('center: {:^10}'.format(100))   # センター寄せ
print('right : {:>10}'.format(100))   # 右寄せ

print('left  : {:*<10}'.format(100))  # 左寄せ
print('center: {:a^10}'.format(100))  # センター寄せ
print('right : {:鬼>10}'.format(100)) # 右寄せ
```
left : 100
center: 100
right : 100
left : 100*******
center: aaa100aaaa
right : 鬼鬼鬼鬼鬼鬼鬼100

**0埋め**

ゼロ埋めして桁数を合わせたい場合は
埋める文字を0に指定して右寄せします。

`{:0桁数}.format(数値)`

```
# 5けたで0埋め
print('zero padding: {:05}'.format(123))
```
zero padding: 00123

**桁区切り（カンマ、アンダースコア）**

3ケタ毎に`,`カンマまたは'_'アンダースコアの区切りを入れられます。

`{:,}.format(数値)`
`{:_}.format(数値)`
なお、`_`アンダースコアはPython3.6で追加されたオプションなので
バージョンが古い場合は使えません。

```
# カンマで3ケタ区切り
print('{:,}'.format(100000000))

# _ で3ケタ区切り #print('{:_}'.format(100000000))
100,000,000
```

**小数点以下の桁数指定**

全体の桁数を指定するには `.` のあとに桁数を書きます。
小数点以下の場合は固定小数点数を表す `f` を付けます。

`{:.桁数}.format(数値)`
`{:.桁数f}.format(数値)`

```
#2桁分まで表示
print('{:.2}'.format(1.234321))
 #5桁分まで表示
print('{:.5}'.format(21.23432))

# 小数点5桁分
print('{:.5f}'.format(221.234543))
```
1.2
21.234
221.23454

## 算術演算子

[![表示されなかったらすみません](https://img.youtube.com/vi/99ijaVYKD_c/0.jpg)](https://youtu.be/99ijaVYKD_c)

プログラミング言語の中では各種の演算を表わす記号・シンボルが存在します。
それを「演算子」と言っています。

大きく四つに分けると

1.算術演算子(代数)
2.代入演算子
3.関係演算子(比較)
4.論理演算子
になります。

今回はその中で　「算術演算子」　についてとり扱っていきます。

**算術演算子(または代数演算子)**

算術演算子は四則計算をするのに使われる「演算子」です。


|記号|意味|
|:--:|:--:|
|+|加算(足し算))|
|-|減算(引き算)|
|*|乗算(掛け算)|
|/|除算(割り算)|
|%|剰余(余り)|
|**|べき乗|

`+`足すプラス　と　`-`引くマイナス　は　そのままですが
掛け算と割り算では使える記号が変わります。

掛け算は　`*`アスタリスク
割り算は　`/`スラッシュ
その他、珍しいものでは`%`剰余があります。

```
# 足し算(加算)
1+2

# 引き算(減算)
1-3

# かけ算(乗算)
2*3

# 割り算(除算)
```
10/3
3
2
6
3.3333333333333335

Python3では`/`スラッシュ１つの場合は結果は小数点まで出ます。

整数値だけにしたい場合は`//`スラッシュを二つ重ねます。
これで切り捨て除算になります。　

```
# 割り算(余りなし、切り捨て除算)
10//3
# べき乗
2**3
```

べき乗の記号を用いてルート計算もできます。

```
# ルート
print(2**0.5)
print(9**0.5)
```
1.4142135623730951
3.0

特殊な演算方法として剰余といいますが
割った際の余りを求める方法です。

余りを求める際には　`%` の記号を使います。

```
# 剰余(割った際の余り)
print(5%3)
print(5%2)
print(5%5)
```
2
1
0

この余りという計算は、プログラム内では様々な条件分岐や
判定に応用できます。

```
# 掛け算や引き算の優先順位は算数と一緒
2 * 3 + 4
```
10


足す、引くを優先したい場合は `()` カッコを用いる

```
a,b,c = 2,3,4
d = a * b + 4
e = a * (b + 4)
print(d)
print(e)
```
10
14

四則計算はプログラミングの基本になるので
しっかりと書き方を覚えておきましょう。

## 代入演算子

[![表示されなかったらすみません](https://img.youtube.com/vi/ts4_VpXR5TE/0.jpg)](https://youtu.be/ts4_VpXR5TE)

プログラミングではデータを格納することを
「代入」といっています。

その代入の仕方に関わる演算子が「代入演算子」です。

代入は `=` イコール　記号となります。

文字を代入する場合は　`'`シングルクォートや`"`ダブルクォートで囲み
数値を代入する場合は　そのまま数字を入力します。

```
# 変数a　に数値 121を代入
a = 121
print(a)
```
121

「代入」は`=`イコールの左側にある変数に
右側の計算結果を入れ込むような働きをします。

```
# 変数 a , b を用意
a , b = 2 , 3
print(a)

# a = a + b と同じ意味合い
a += b
print(a)
```
2
5

`a` に `b`　を足した結果を　再度 `a`に代入する　ということになります。
`a = a + b` と同じ意味合いになります。
結果は 最初に `a`　に`2` ,  `b` に `3`が入っているので `2 + 3`　が
`a`の中に入ります。

この代入演算子を使った方法はプログラムでよく用いられます。
特に `+=1`　でその変数の値を1ずつ足していく方法は
かなりの頻度で用いられます。

その他の「代入演算子」について

```
a = b         # a に b を代入する
a += b        # a = a + b に同じ
a -= b        # a = a - b に同じ
a *= b        # a = a * b に同じ
a /= b        # a = a / b に同じ
a %= b        # a = a % b に同じ
a **= b       # a = a ** b に同じ
a //= b       # a = a // b に同じ
```
左側の変数に、右側の変数を足したり引いたりした
結果を代入するというようなことが行えます。

```
# 変数 a , b を用意
a , b = 2 , 3

print(a)

# 何度か足してみる
a += 2
a += 5
print(a)
```
2
9

代入するたびに変数の値は変化します。

この１行で変数の中身が大きく変化していきますので
どこでどう値を変更しているのかといったことが
すぐに把握できるように、演算子の使い方は押さえておきましょう。


## 関係演算子

[![表示されなかったらすみません](https://img.youtube.com/vi/n1HzEVE1AH8/0.jpg)](https://youtu.be/n1HzEVE1AH8)


`=`イコール一つの場合は代入で値を格納することになりました。

`==`イコールを二つ用いると、今度は左側と右側を比較する動きになります。

比較のしかたが複数あり、演算子も複数存在します。
こういった比較をする演算子を、関係演算子や比較演算子と言っています。

**数値の比較**

まずは数値のデータを用意します。

変数 `a` と `b` を用意して

```
a , b = 2 , 3
```

`==` : 演算子の左と右が等しいかどうかを判定する
等しい場合は`True` , 等しくない場合は`False`が返ってきます。

```
# a が b と等しいかどうかの判定
a == b
```
False

`!=` : 演算子の左と右が等しくないかどうかを判定する 
等しくない場合は`True` , 等しい場合は`False`が返ってきます。

```
# a が b と異なるかどうかの判定
a != b
```
True

`<`演算子の左が右より小さいか比較する

演算子の左側が右側よりも小さい(未満)であったら`True`
違えば`False`が返ってきます。

```
# a が b よりも小さい(未満)　小なり
a < b
```
True

`>`演算子の左が右より大きいか比較する

演算子の左側が右側よりも大きければ`True`
違えば`False`が返ってきます。

```
# a が b よりも大きい　大なり
a > b
```
False

大なり小なりに`=`イコールをつけると、以上と以下という意味になります。

`<=` : 演算子の左側が右側以下であれば`True` , 違えば `False`　が返ってきます。

```
# a が b 以下である　小なりイコール
a <= b
```
True

`>=`:演算子の左側が右側以上であればTrue , 違えば False　が返ってきます。

```
# a が b 以上である　大なりイコール
a >= b
```
False

大小を比較する演算子は数値の計算にしか
正しく用いることができませんので
変数に格納するデータの形には注意して下さい。

**文字列の比較**

文字列の比較は

`is`    (等しいかどうかの判定)
`not` (否定)
`in`    (含まれるかどうかの判定)

などを用います。

判定が正しければ `True` , 正しくなければ `False` を返します。

```
a , b = 'a' , 'b'

# a が b と等しいかどうかの判定
print(a is b)           

# a が b と異なるかどうかの判定
print(a is not b)       

# a が b に含まれるかどうかの判定
print(a in b)   

# a が b に含まれないかどうかの判定
print(a not in b)
```
False
True
False
True

特に文字が含まれるかどうか、という判定はよく用いられます。

文字の検索結果を利用したプログラムの制御は頻繁に出てきますので
`in` 演算子　を使った比較の方法は押さえておきましょう。

このように文字や数値を比較すると
その結果は `True` or `False`　の `bool`型で返ってきます。

比較した結果を用いてプログラムを制御する方法が
プログラムでは多用されるので書き方は覚えておきましょう。



## 論理演算子

[![表示されなかったらすみません](https://img.youtube.com/vi/wCpVE-CqKEQ/0.jpg)](https://youtu.be/wCpVE-CqKEQ)

「論理演算子」は比較の結果同士を加算した結果を返します。
幾つかの条件を組み合わせる場合には必ず用いる方法です。

論理演算子　としては 3つしかありません。

`and`
`or`
`not`

**and**

`and` は条件と条件をつなげます。
日本語だと　`かつ`　という意味合いになります。

`条件A and 条件B`

条件が双方が `True` の場合に `True`
どちらか一方でも`False`なら結果が`False`になります。

`and` の左側と右側の両方の条件を満たしていないと
`True`にはなりません。

```
# 二つの条件がTrue
print(True and True)

# 片方の条件がFalse
print(True and False)
print(False and True)

# 両方の条件がFalse
print(False and False)
```
True
False
False
False

```
# 数値型での例
print(1==1 and 2==2)
print(1==1 and 2==1)
```
True
False

男性、20代の人のような複数の条件を満たす判定を
行いたいような時に使います。

```
a , b = 20 , '男性'
print(a==20 and b == '男性')
```
True

**or**

`or`の左側と右側、どちらかの条件が`True`であれば`True`を返します。
日本語の意味だと　`もしくは`　という意味合いです。

`条件A or 条件B`

両方満たしていれば`True`
どちらか一方でも合っていれば`True`が返ってきます。
両方の条件を満たせない場合のみ`False`が返ってきます。

```
# 二つの条件がTrue
print(True or True)

# 片方の条件がFalse
print(True or False)
print(False or True)

# 両方の条件がFalse
print(False or False)
```
True
True
True
False

```
# 両方の条件を満たす場合
a , b = 20 , '男性'
print(a==20 or b == '男性')

# どちらかの条件を満たす場合
a , b = 20 , '男性'
print(a==30 or b == '男性')

# 両方の条件を満たさない場合
a , b = 20 , '男性'
print(a==30 or b == '女性')
```
True
True
False


**not**
`not`は否定する意味合いになり、結果をひっくり返します。

`True` は`False`に　、　`False`は`True`にします。

```
# 含む場合
d = '男性'
print('男'  in d)
```
True

```
# 含まれないとしたい場合
d = '男性'
print('男'  not in d)
```
False

プログラムの中での制御は比較演算子と論理演算子を組み合わせて
どう処理を分岐させるか、続けさせるのかを組み上げていきますので
論理演算子の使い方も覚えておきましょう。

**論理演算のまとめ**

|論理演算|結果|
|:-:|:-:|
|True and True|True|
|True and False|False|
|False and True|False|
|False and False|False|
|True or True|True|
|True or False|True|
|False or True|True|
|False or False|False|



## まとめ

文字列はプログラムの中でも最もよく出てくるデータの形です。
そのため操作方法などが多岐に渡ります。

データをファイルから読み込んだり、書き出す場合は
文字列として入出力が行われるので
文字列の操作方法はかなり大事です。

演算子もプログラムの制御に関わるものばかりです
どの条件の時に、どんな値を返すのか、どう結果になるのかを
押さえておきましょう。



君がエンジニアになるまであと74日

## 作者の情報
乙pyのHP：
http://www.otupy.net/

Youtube：
https://www.youtube.com/channel/UCaT7xpeq8n1G_HcJKKSOXMw

Twitter：
https://twitter.com/otupython