今さらPython3 (22) - While

この本の第4章を読んでます。

入門 Python 3

入門 Python 3

Whileは難しい?

>>> while count <= 5:
...     print(count)
...     count += 1
...
1
2
3
4
5
>>>

昔(てか今もか)、他の言語でWhile文を作る時になんとも面倒だなと思っていたのが、While文の条件のところ。while文自体に条件を付けたり、Pythonにはないけどendwhileのところにも条件を付けられたりと、便利ではあるけど少し怖いなと思いながら使っていたけど、pythonの場合はシンプルに書けそうなので幾分気持ちが楽。

とか言いながら、最後のcount+=1を忘れて無限ループさせちゃったりするんだけど(苦笑)

>>> while True:
...     stuff = input("String to capitalize [type q to quit]: ")
...     if stuff == 'q':
...         break
...     print(stuff.capitalize())
...
String to capitalize [type q to quit]: abc
Abc
String to capitalize [type q to quit]: bcd
Bcd
String to capitalize [type q to quit]: quize
Quize
String to capitalize [type q to quit]: q
>>>

whileの中で条件を満たした場合にbreakするのが、この上の例ですと。実際には、文字を入れた後にEnterするので、quizeみたいなq始まりの単語でも大丈夫ですね。

continueの使い方

>>> while True:
...   value = input("Integer, please [q to quit]:")
...   if value == 'q':   #quit
...       break
...   number = int(value)
...   if number %2 == 0:    #an even number
...       continue
...   print(number, "squared is", number*number)
...
Integer, please [q to quit]:1
1 squared is 1
Integer, please [q to quit]:2
Integer, please [q to quit]:3
3 squared is 9
Integer, please [q to quit]:4
Integer, please [q to quit]:5
5 squared is 25
Integer, please [q to quit]:6
Integer, please [q to quit]:7
7 squared is 49
Integer, please [q to quit]:2.6
Traceback (most recent call last):
  File "<stdin>", line 5, in <module>
ValueError: invalid literal for int() with base 10: '2.6'
>>> int(2.6)
2
>>>

continueというのは、whileブロックの中にcontinue以下の処理を飛ばして次のループを処理するという理解でOKそう。1つ気になるのは、2.6というfloatを渡したときにエラーとなった辺りかな。インタプリタでint(2.6)を渡すと丸めてくれるのに、何で挙動が違うんだろうか?

ということで、インプットした値がどういう型(type)で渡されるかを出力する1行を追加して再トライ。

>>> while True:
...   value = input("Integer, please [q to quit]:")
...   if value == 'q':   #quit
...       break
...   print(type(value))
...   number = int(value)
...   if number %2 == 0:    #an even number
...       continue
...   print(number, "squared is", number*number)
...
Integer, please [q to quit]:1
<class 'str'>
1 squared is 1
Integer, please [q to quit]:2
<class 'str'>
Integer, please [q to quit]:3
<class 'str'>
3 squared is 9
Integer, please [q to quit]:4
<class 'str'>
Integer, please [q to quit]:5
<class 'str'>
5 squared is 25
Integer, please [q to quit]:2.6
<class 'str'>
Traceback (most recent call last):
  File "<stdin>", line 6, in <module>
ValueError: invalid literal for int() with base 10: '2.6'
>>>

これを見ると、input文で入力した場合は、いったんstrとして格納される訳ですね。

>>> int(str('2.6'))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: '2.6'
>>> int(str('2'))
2
>>>

文字型の'2.6'を直接intには変換できないと。動作としては理解。

while...else

これは意識して使ったことがないパターンかも。

>>> numbers = [1, 3, 5]
>>> position = 0
>>> while position < len(numbers):
...     number = numbers[position]
...     if number % 2 == 0:
...         print('Found even number', number)
...         break
...     position += 1
... else:  #break not called
...     print("No even number found")
...
No even number found

breakが呼び出されなかった場合は、elseのブロックが処理されるということね。

>>> numbers = [1, 2, 3, 6]
>>> while position < len(numbers):
...     number = numbers[position]
...     if number % 2 == 0:
...         print('Found even number', number)
...         break
...     position += 1
... else:  #break not called
...     print("No even number found")
...
No even number found
>>> numbers
[1, 2, 3, 6]
>>> position
4
>>> position = 0
>>> while position < len(numbers):
...     number = numbers[position]
...     if number % 2 == 0:
...         print('Found even number', number)
...         break
...     position += 1
... else:  #break not called
...     print("No even number found")
...
Found even number 2
>>>

じゃ、偶数がある場合にどうなるの?と思って試したら結果が変だと思った時の履歴。単純にpositionの初期化を忘れていて、処理した時点でpositionが4になっていたので直接elseブロックに飛んでいた事が判明。

(つづく)