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

今回もPythonの基礎の続きです。
早いものでもう30日目ですね。
なんだか終わる気がしないwww。


前回はこちら
[100日後にエンジニアになるキミ - 29日目 - Python - Python言語の基礎5]
(https://qiita.com/otupy/items/22d4ab97b33c989ab284)


## 組み込み関数について


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

pythonでは標準の機能として
組み込み関数というのが備わっています。

この講座のはじめから使っている
print()関数なども組み込み関数です。

プログラムには欠かすことのできない機能であるため
組み込み関数の使い方を学んでいきましょう。

**関数の使い方**

`関数名(引数,・・・)`

関数名の後の`()`カッコに指定するものを`引数`と言い
`引数`は関数によっては複数存在することもあります。

その場合は`,`カンマで区切ることで、
何番目の`引数`に該当するかを指定できます。

関数を実行した結果は、何かしらの値が返ってくることがあります。
この返却される値のことを`戻り値`と言っています。

**様々な組み込み関数**

***abs関数***

数の絶対値を返す。
`abs(数値)`

```python
print(abs(2.5))
print(abs(-12.2))
```
2.5
12.2

**int関数**
文字列や小数点を整数値に変える。
文字列の場合は数字のみで整数のみ、小数点はエラー
数値の場合、小数点以下は切り捨てとなる。

```python
print(int(12.3))
print(int('13'))
print(int(0.9))
```
12
13
0


***float関数***

文字や整数値から浮動小数点の値に変える。
文字は数字でなくてはダメ。文字も小数点と数字だけ。

`float(文字列)`
`float(整数値)`

```python
print(float(13))
print(float('15.5'))
```
13.0
15.5

***oct関数***

数値を8進法の値に変換
`oct(数値)`

```python
print(oct(8))
print(oct(2))
```
0o10
0o2

***hex関数***

数値を16進法の文字列に直す
`hex(数値)`

```python
print(hex(255))
print(hex(16))
```
0xff
0x10


`0x`が付くのは16進法の表記法
0から始まって16になると桁が繰り上がる。

16進数の先頭の`0x`付きや無しに変換したい場合は
`format`関数を用いて実現できます。

```python
print(format(255 , 'x'))
print(format(255 , 'X'))
print(format(255 , '#x'))
```
ff
FF
0xff

***input関数***

入力欄が出てきて
プログラムに対して入力を行うことができる。

`input('文字列')`

```python
s = input('--> ') 
print(s)
```
--> 入力したよ

入力したよ

***len関数***
引数に指定したオブジェクトの長さを返す。
`len(オブジェクト)`

```python
a = 'こんにちは、マット・デイモンです。'
# 文字数を返す
print(len(a))
```
17

```python
b = [1,2,3,4,5]
# リストの要素数を返す
print(len(b))
```
5

***list関数***
引数に指定したオブジェクトをリスト型に変換

`list(オブジェクト)`

```python
# 辞書型を定義
d1 = {1:2,3:4,5:6}
print(d1)

# キーをリストに変換
print(list(d1.keys()))

# 値をリストに変換
print(list(d1.values()))

# キーと値のタプル型の要素を持つリストに変換
print(list(d1.items()))
```
{1: 2, 3: 4, 5: 6}
[1, 3, 5]
[2, 4, 6]
[(1, 2), (3, 4), (5, 6)]

***dict関数***

キーと値の２つの組み合わせになっているものであれば辞書型に変換できる。

`dict(オブジェクト)`

```python
# タプル型の要素を持つリストを辞書に変換
d2 = dict([('k1', 1), ('k2', 2), ('k3', 4)])
print(d2)
```
{'k1': 1, 'k2': 2, 'k3': 4}

***max,min関数***

`max`関数は複数指定したオブジェクトの中で、一番大きなものを返す。
`min`関数はその逆で、最小の値を返す。

`max(オブジェクト)`
`min(オブジェクト)`

```python

sample_list = [1,2,3,4,5,6]
# 最大値を返す
print(max(sample_list))
# 最小値を返す
print(min(sample_list))
```
6
1

```python
sample_st= 'apple'
# 最大値を返す
print(max(sample_st))
# 最小値を返す
print(min(sample_st))
```
p
a

***open関数***

ファイルを開いてファイルオブジェクトを作る関数。
こちらは紹介だけで、後の講義で詳細解説。

`open(ファイルパス)`

***range関数***

引数に指定した回数分のオブジェクトを生成する。

`range(回数)`
`range(開始 , 終了)`
`range(開始 , 終了 , 間隔)`

```python
# 4つの整数を生成
print(list(range(4)))
```
[0, 1, 2, 3]

***round関数***

小数点を丸めて、一番近い整数を返す。
`round(数値)`

```python
print(round(3.499)) 
print(round(3.5))
```
3
4

第二引数に桁を追加すると、その小数点の桁数で丸めを行う。

```python
print(round(3.5187,3))
print(round(3.5187,1))
```
3.519
3.5

***sorted関数***

引数に指定したオブジェクトの要素の並び替えを行う。
sorted関数の詳しい使い方に関しては後のソートの講義で
`sorted(オブジェクト)`


***str関数***
引数に指定したものを文字列に変換
`str(オブジェクト)`

```python
# 整数値を文字列に変換
print(str(12))
```
12

***sum関数***

リスト型の要素の合計値を返す。
要素が数値で無いとダメ

```python
li =[1,2,3,4]
print(sum(li))
```
10


***zip関数***
***enumerate関数***

詳細は後の講義で。

関数は複数を組み合わせて使うことも可能

```python

# 文字を小数点にしてから整数値に変換して絶対値にする。
print(abs(int(float('-3.14'))))
```
3

組み合わせた際は、カッコの最も内側に有るものの処理が先に行われます。

関数ではこのように複数を組み合わせて使って行くのが一般的になりますが
処理が複雑になり、追って行くのも大変になります。

まずは一番初めに処理が行われる部分を探して、その結果が正しいのか
ということを一つ一つ追って行くのが良いと思います。



## enumerate関数

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

さて`for文`で繰り返しの書き方をやりましたが、覚えていますか
`for文`の書き方のおさらいです。

`for文`では`range`関数などを使って繰り返しの回数を指定していました。

```python

for i in range(5):
    print(i)
```
0
1
2
3
4


このようにすると`range`関数には0から4までの数値が生成され、
`for文`としては５回処理が繰り返されます。

`enumerate`関数はこの`for文`の処理に
`回数を数える変数`を付け足すことができます。

```python
# 5から9までの整数を生成して繰り返し処理する。
for i , j in enumerate(range(5,10)):
    print(i , j)
```
0 5
1 6
2 7
3 8
4 9


どんな時に使うかというと処理が行われた回数を数えて、
回数で処理を抜けるような場合に用いる事が多いです。

```python

count = 0
for i in range(5):
    print(i)
    if i>=3:
        break
    count+=1
```
0
1
2
3

```python

for i , j in enumerate(range(5)):
    print(i,j)
    if i>=3:
        break
```
0 0
1 1
2 2
3 3

無駄な変数への代入などを省いて、コードを簡略化でき
バグを少なくすることができるのがこの関数の利点です。

`for文`などで繰り返しの回数をカウントしたり、値として
用いたりするのに役立つ関数になっているので
繰り返しの処理を書く際には便利な関数です。


## zip関数

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

zip関数はリスト型を２つ用いて繰り返しの中などで
同時に使うことをできるようにする関数です。

`zip(オブジェクト,オブジェクト)`

まずはリスト型の変数を二つ用意し
これをfor文で使っていきます。

```python

a = [1,2,3,4,5]
b = [6,7,8,9,0]

for i , j in zip(a,b):
    print(i,j)
```
1 6
2 7
3 8
4 9
5 0

変数`i` , `j` にはそれぞれ元のリスト型の変数の値が
格納されることになります。

もし`zip`関数を用いないで、２つのリストを使おうとすると
こんな感じになってしまいます。

```python
a = [1,2,3,4,5]
b = [6,7,8,9,0]

count=0
for i in a:
    print(i , b[count])
    count+=1
```
1 6
2 7
3 8
4 9
5 0

当然バグの元にもなり得るので
処理としてまとめられるのであれば
`zip`関数を使ってしまった方が楽でコードもスッキリします。

また`zip`関数で使えるリスト型のデータについては
同じ要素数である必要があります。


## ソート

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

ソートはデータを並べ替えを行います。
プログラムの中ではかなり多く用いられる処理です。

**文字列型の並び替え(逆順にする)**

インデックスを用いて文字列を逆さまにすることができます。

`文字列[::-1]`

```python
a1 = 'abcdeアイウエオ123幹事!'
# [::-1]で逆さまにする
print(a1[::-1])
```
!事幹321オエウイアedcba

文字列内で使われている文字を並び替えるには
一旦`リスト型`に変換してから並び替えし、`文字列`に戻すことで
文字列の並び替えを実現できます。

`sorted`関数を使うと、文字列を分割して並び替えを行います。
第二引数の`reverse`に`True`を指定すれば降順
`False`を指定するか第二引数なしの場合は昇順となります。

```python
a2 = 'abcdeアイウエオ123幹事!'
# sorted関数でリストに変換して昇順ソート
print(sorted(a2,reverse=False))

# sorted関数でリストに変換して降順ソート
print(sorted(a2,reverse=True))
```
['!', '1', '2', '3', 'a', 'b', 'c', 'd', 'e', 'ア', 'イ', 'ウ', 'エ', 'オ', '事', '幹']
['幹', '事', 'オ', 'エ', 'ウ', 'イ', 'ア', 'e', 'd', 'c', 'b', 'a', '3', '2', '1', '!']

`join`関数を用いるとリスト型のものを１つづつ連結して
文字列にすることができます。

`'連結文字列'.join(リスト型)`

```python
a3 = 'abcdeアイウエオ123幹事!'
print(''.join(sorted(a3 , reverse=True)))
```
幹事オエウイアedcba321!

あまり文字列だけでの並び替えは
使う機会がないかもしれませんが、いざという時に役立つ手法です。

**リスト型のソート**

リスト型の関数であるsort関数を使う方法と
sorted関数を用いる方法があります。


***sort関数***

昇順：`変数名.sort()`
降順：`変数名.sort(reverse=True)`

***sorted関数***

昇順：`sorted(変数名)`
降順：`sorted(変数名,reverse=True)`

どちらも似ていますが
sort関数はリストの並び替えを行い、リスト型の並び順が変わります。
sorted関数は一時的な並び替えを行うので、元のリストの並び順に影響しません。

```python
lis1= [3,1,2,4,5,7,6]
print(lis1)

# 昇順ソート
print(sorted(lis1))

# sorted関数の後に再度呼び出しても順番は変わら無い
print(lis1)
```
[3, 1, 2, 4, 5, 7, 6]
[1, 2, 3, 4, 5, 6, 7]
[3, 1, 2, 4, 5, 7, 6]

```python
lis2= [3,1,2,4,5,7,6]
print(lis2)

# 降順にソート
lis2.sort(reverse=True)
# sort関数の後に呼び出すと順番は変わる
print(lis2)
```
[3, 1, 2, 4, 5, 7, 6]
[7, 6, 5, 4, 3, 2, 1]

順番がプログラムに大きな影響を与える場合は注意が必要です。

元の形を保持したままにするのか、並び替えてから使うのか
処理のさせ方を考えて使い分けをします。



**辞書型のソート**

辞書型の並び替えは
`キーの昇順`と`キーの降順`
`値での昇順`と`値での降順`
この4通りが存在します。

キー昇順：`sorted(辞書型の変数.items())`
値の昇順：`sorted(辞書型の変数.items(), key=lambda x:x[1])`
キー降順：`sorted(辞書型の変数.items(), reverse=True)`
値の降順：`sorted(辞書型の変数.items(), key=lambda x:x[1],reverse=True)`

```python
# キー昇順
dct = { 2:3, 3:4, 1:2, 0:8, 4:2 }
for k, v in sorted(dct.items()):
    print(k,':',v)
```
0 : 8
1 : 2
2 : 3
3 : 4
4 : 2

```python
# キー降順
dct = { 2:3, 3:4, 1:2, 0:8, 4:2 }
for k, v in sorted(dct.items(), reverse=True):
    print(k,':',v)
```
4 : 2
3 : 4
2 : 3
1 : 2
0 : 8

```python
# Value昇順
dct = { 2:'3', 3:'4', 1:'2', 0:'8', 4:'2' }
for k, v in sorted(dct.items(), key=lambda x:x[1]):
    print(k,':',v)
```
1 : 2
4 : 2
2 : 3
3 : 4
0 : 8

```python
# Value降順
dct = { 2:'3', 3:'4', 1:'2', 0:'8', 4:'2' }
for k, v in sorted(dct.items(), key=lambda x:x[1],reverse=True):
    print(k,':',v)
```
0 : 8
3 : 4
2 : 3
1 : 2
4 : 2

`lambda`というのはラムダと読み、
pythonでは`無名の関数`を表す`予約語`になります。

ラムダについては後の講義で詳しくやって行きたいと思いますので、
ここでは割愛しますが、辞書の値で並び替えするには、
こういった書き方をしなくてはいけません。

辞書型そのものは並び順が大きな意味を持たないデータ型であるので
それを使うときにだけ並び替えを行うのが一般的です。

例えば、最終的に上位1番だけを出力する
といった時には降順で並び替えて出力する、ということを行います。

```python
dct = { 2:'3', 3:'4', 1:'2', 0:'8', 4:'2' }

# まず辞書を値の降順ソートしてからenumrate関数に組み込む
for i , d  in enumerate(sorted(dct.items(), key=lambda x:x[1],reverse=True)):
    if i>=1:
        # 2回目で処理を抜ける
        break
    print(i,d[0],d[1])
```
0 0 8


繰り返しの処理を行う際にまず、辞書を値の降順でソートしておきます。
`enumerate`関数から返されるカウント数をみて繰り返しの処理を抜けます。

そうすることでデータが大量にある際に、上位何番まで出力するといった
ことも実現できるようになります。

注意点としては`enumerate`関数と辞書型の`items`を使うと
返ってくるデータ型は数値型とタプル型なので気をつけてください。

pythonでは`sorted`関数を用いることで、
様々な形のデータの並び替えを行うことができます。

並びが重要なものを取り扱うプログラムを作るのに役立つと思います。

## 内包表記

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

内包表記はpython独特の書き方で
一定の処理を簡素に書くための手法となります。

**内包表記の書き方**

リスト：`[値 for 変数 in イテラブルオブジェクト]`
辞書　：`{キー:値 for 変数 in イテラブルオブジェクト}`
セット：`{値 for 変数 in イテラブルオブジェクト}`


**内包表記を使ってリストを作る**

`[値 for 変数 in イテラブルオブジェクト]`

```python
# 内包表記で変数にリスト型を格納する
lis1 = [i for i in range(10)]
print(lis1)
```
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

内包表記を使わない場合は

```python
lis2 = []
for i in range(10):
    lis2.append(i)
print(lis2)
```
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

内包表記は複数行にわたる処理を１行にまとめる事ができます。

**内包表記を使って辞書を作る**

`{キー:値 for 変数 in イテラブルオブジェクト}`

```python
# 内包表記でキーをenumerate , 値をrangeの結果として辞書型を作成
num_dict = {k:v for k,v in enumerate(range(2,30,3))}
print(num_dict)
```
{0: 2, 1: 5, 2: 8, 3: 11, 4: 14, 5: 17, 6: 20, 7: 23, 8: 26, 9: 29}

keyとvalueに該当するものが有れば辞書型を作成可能です。
内包表記の中では`IF文`を用いることもできます。

**内包表記 ＋ IF文**

リスト：`[値 for 変数 in イテラブルオブジェクト if 条件]`
辞書 ：`{キー:値 if 条件 for 変数 in イテラブルオブジェクト}`

**内包表記 ＋ IF , else文**

リスト：`[値1 if 条件 else 値2 for 変数 in イテラブルオブジェクト ]`
辞書：`{キー1 if 条件 else キー2 : 値1 if 条件 else 値2 for 変数 in イテラブルオブジェクト}`

```python
# リスト内包表記 + IF文
num_list = [i for i in range(15) if i%2==0]
print(num_list)
```
[0, 2, 4, 6, 8, 10, 12, 14]

```python
# リスト内包表記 + IF , else文
num_list = [i if i%2==0 else 0 for i in range(15) ]
print(num_list)
```
[0, 0, 2, 0, 4, 0, 6, 0, 8, 0, 10, 0, 12, 0, 14]

```python
# 辞書内包表記 + IF文
num_dict = {k:v for k,v in enumerate(range(2,30,3)) if k%2==0}
print(num_dict)
```
{0: 2, 8: 26, 2: 8, 4: 14, 6: 20}

```python
# 辞書内包表記 + IF , else文
num_dict = {k if k%2==0 else 0 : v if k%2==0 else 0  
for k,v in enumerate(range(2,30,3)) }
print(num_dict)
```
{0: 0, 8: 26, 2: 8, 4: 14, 6: 20}


辞書型は`enumerate`関数を用いずに`zip`関数で
リスト２つを用いたりしても作る事ができます。

```python
lis_a = [1,2,3,4,5]
lis_b = ['a','b','c','d','e']
d2 = {k:v for k,v in zip(lis_a,lis_b)}
print(d2)
```
{1: 'a', 2: 'b', 3: 'c', 4: 'd', 5: 'e'}


リスト内包表記IFELSE文から辞書を作成する事もできます。

```python
# リスト内包表記から辞書化
num_dict = dict((str(i),i) if i%2==0 else (i,str(i)) for i in range(10))
print(num_dict)
```
{9: '9', 1: '1', 3: '3', '8': 8, 5: '5', '0': 0, '2': 2, '4': 4, '6': 6, 7: '7'}

内包表記の中で`for文`は複数書くことができます。

`[値 for 変数1 in イテラブルオブジェクト for 変数2 in イテラブルオブジェクト]`

```python
# 2重の内包表記
print([i*j for i in range(1,5) for j in range(1,4) ])
```
[1, 2, 3, 2, 4, 6, 3, 6, 9, 4, 8, 12]

これを通常のfor文で書いて見ましょう。

```python
a5 = []
for i in range(1,5):
    for j in range(1,4):
        a5.append(i * j)
print(a5)
```
[1, 2, 3, 2, 4, 6, 3, 6, 9, 4, 8, 12]

後に書いた方が内側のfor文に該当します。

このように複数行に渡るものも1行でスッキリ書くことができるのが
内包表記の良いところです。

まずは通常の処理を正しく書くことから始め、
それを簡略化できる部分があれば、内包表記に変えてゆく
といった風にすると、上手に覚えることができると思います。


## まとめ

Pythonでは標準の機能としての関数が多く備わっており
無駄なコードを沢山書かなくても同様の処理を
少ないコード量で行うことができます。

関数を組み合わせることで
よりコード量を少なくできることもできますので
よく用いられる関数の挙動を覚えておくと楽です。

ソートはデータの並び替えをする際には必ず行われるので
どう並び変えるのか、どうコードを書けば良いのかを
押さえておきましょう。

内包表記はPython特有の表記方法ですが
複数行に渡る処理を1行で書くことができ
コード量の短縮や、実行時間の短縮に繋がります。

コード量が少ないことはバグの発生を抑えたり
デバッグの時間短縮にも繋がりますので
Python特有の書き方を覚えて行きましょう。


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

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

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

Twitter：
https://twitter.com/otupython