Python の for 文ってなに?





ひとつ、ひとつ、順番に
オブジェクトを
取り出す時に使います。





f:id:domodomodomo:20180805030321j:plain f:id:domodomodomo:20180805030327j:plain f:id:domodomodomo:20180805143745j:plain f:id:domodomodomo:20180805143749j:plain








この記事は Python の for 文とは何か、動作の仕組みについて説明していて、Python の for 文の使い方については説明していません。

f:id:domodomodomo:20180805014814j:plain

1. 基本的な書き方

in の中にはオブジェクトの集まりがはいります。

for 変数 in オブジェクトの集まり:
   繰り返す処理

◯ 実例

# range
for integer in range(3):
    integer

# list
for fruit in ['orange', 'apple', 'grape']:
    fruit

# set
for element in {'Japan', 'China', 'United States'}:
    element

# dict
for key in {'香川真司': 10, '本田圭佑': 4, '長谷部誠': 17}:
    key

2. range って、なに?

答え: range は整数の集まりです。 f:id:domodomodomo:20180805143805j:plain f:id:domodomodomo:20180805143809j:plain f:id:domodomodomo:20180805143819j:plain f:id:domodomodomo:20180805143826j:plain f:id:domodomodomo:20180805143833j:plain f:id:domodomodomo:20180805030512j:plain f:id:domodomodomo:20180805030535j:plain


"in にはオブジェクトの集まりはいります" って言ったけど、range は別にオブジェクトの集まりではなくない?という疑問があります。

ここでは数字の集まりだと考えておいてください。 range(10) なら 0 ~ 9 までの数字です。range(0, 10, 2) なら 0 ~ 9 までの数のうちの偶数となります。

>>> # range(10) は 0 ~ 9 のオブジェクトの集まりです。
>>> r = range(10)
>>> r[0]
0
>>> r[1]
1
>>> r[2]
2
>>> r[3]
3
>>> r[4]
4
>>> r[5]
5
>>> r[6]
6
>>> r[7]
7
>>> r[8]
8
>>> r[9]
9
>>>
>>> r = range(0, 10, 2)
>>> r[0]
0
>>> r[1]
2
>>> r[2]
4
>>> r[3]
6
>>> r[4]
8
>>> 

range 型は、数のイミュータブルなシーケンスを表し、 一般に for ループにおいて特定の回数のループに使われます。
4.4.6. range - Python 標準ライブラリ


immutable というのはオブジェクトの値を変更できないということ。 シーケンスというのは seq[0] のように属性を番号で参照できるオブジェクトのことです。具体的には list, tuple, str が該当します。

>>> # 変更できない
>>> r[0] = 777
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'range' object does not support item assignment
>>> 
>>> # 実は str もシーケンス
>>> s = 'Hello, world!'
>>> s[0]
'H'
>>> 

◯ 復習

for 文は、集まりからオブジェクトを一つずつ取り出す処理を行います。

もちろん range は、何回か繰り返す処理をする時に使うと覚えておいても問題はないですが、基本的には整数の集まりと認識しておくと for 文の理解が進みます。

3. 二重の for 文(第一関門)

f:id:domodomodomo:20180805030846j:plain

二重の for 文は、ひとつのつまずきどころかなと思ったりします。

# バブルソート
def bubble_sort(lst):
    n = len(lst)
    for i in reversed(range(n)):
        for j in range(i):
            if lst[j] > lst[j + 1]:
                lst[j], lst[j + 1] = lst[j + 1], lst[j]

lst = [3333, 5123, 9981, 1243, 7412]
bubble_sort(lst)
print(lst)
# [1243, 3333, 5123, 7412, 9981]

Python のバブルソート

4. for 文と while 文の違いって、なに?

for 文 ... 要素をとひとつひとつ取り出して、処理を繰り返す。

while 文 ... 条件が True である限り、処理を繰り返す。

5. for 文の中でリストに代入できないのは、なんで?(第二関門)

f:id:domodomodomo:20180805030905j:plain

リストに全部 None を代入しようとして、昔よく失敗しました。

lst = [0, 1, 2, 3]
for element in lst:
    element = None

lst
# [0, 1, 2, 3]
# あれ?


何をしているかというと、単純に変数 element に代入し続けてるだけだからです。

lst = [0, 1, 2, 3]
# for element in lst:
element = None
element = None
element = None
element = None


正しくは、次のようにします。

for i in range(len(lst)):
    lst[i] = None

lst
# [None, None, None, None]
# うまく行った

6. for 文の中でリストに pop, append, del できないのは、なんで?


順番が崩れてしまうからです。





実は for 文でこう書いたとき

lst = [0, 1, 2, 3, 4, 5, 6 ,7 ,8 ,9]
for e in lst:
    #
    print(e)


while 文で書き直すとこういう動作をしています。

lst = [0, 1, 2, 3, 4, 5, 6 ,7 ,8 ,9]
i = -1
while i < len(lst) - 1:
    i += 1
    e = lst[i]
    #
    print(e)


そのため、例えば for 文の中で先頭からリストを pop してしまうと、2 個ずつ for 文が進んでしまいます。

lst = [0, 1, 2, 3, 4, 5, 6 ,7 ,8 ,9]
for e in lst:
    #
    tmp = lst.pop(0)
    print(e)

# 0
# 2
# 4
# 6
# 8
lst = [0, 1, 2, 3, 4, 5, 6 ,7 ,8 ,9]
i = -1
while i < len(lst) - 1:
    i += 1
    e = lst[i]
    #
    tmp = lst.pop(0)
    print(e)

# 0
# 2
# 4
# 6
# 8


次のイテレータについて説明しているページで、CPython では、実際にそのように実装されていることを紹介します。

◯ 正しくは...

直接 list, dict などの要素を扱いたいときは while 文を使いましょう。

lst = [0, 1, 2, 3, 4, 5, 6 ,7 ,8 ,9]
while lst:  # lst に要素があるならば...
    lst.pop(0)


実は while 文は、単純に "条件が True である限り、処理を繰り返す" だけではなく

for 文 ... 要素をとひとつひとつ取り出して、処理を繰り返す。

while 文 ... 条件が True である限り、処理を繰り返す。

while 文 ... 要素がある限り、処理を繰り返す new!



ということもしています。これについては if 文ってなに?のなかで説明させていただきます。

7. for 文で使えるクラスは、なに?
オブジェクトの集まりって、なに?

import しなくても使えるクラスを "組み込み型" と言います。 この組み込み型のうち for 文で使えるのは、次のクラスです。

# for 文で使える組み込み型の一覧
range
list
tuple
set
dict
str
zip
filter
map
bytearray
bytes
enumerate
frozenset
reversed


具体的には range, tuple, set, dict などのクラスのオブジェクトです。 より正確に言えば、__iter__ メソッドを持つオブジェクトです。

さて、これをどうやって調べたのでしょうか?次のコードを実行すれば、上記の for 文で使えるクラスの一覧が取得できます。

import builtins

builtin_types = [t for t in builtins.__dict__.values() if isinstance(t, type)]
builtin_iterbale_types = [t for t in builtin_types if hasattr(t, '__iter__')]

for t in builtin_iterbale_types:
    print(t)





まとめ

f:id:domodomodomo:20180805031152j:plain f:id:domodomodomo:20180805031205j:plain f:id:domodomodomo:20180805031216j:plain f:id:domodomodomo:20180805031436j:plain f:id:domodomodomo:20180805031258j:plain f:id:domodomodomo:20180805031307j:plain f:id:domodomodomo:20180805031316j:plain f:id:domodomodomo:20180805031521j:plain