coLinux日記

coLinuxはフリーソフトを種として、よろずのシステムとぞなれりける。

SimplePrograms で Python を学ぶ その10

2024-05-02 23:32:20 | Python
SimplePrograms - Python Wiki
https://wiki.python.org/moin/SimplePrograms

の 10番目のプログラムは、Time, 条件, from..import, for..else です。

from time import localtime

activities = {8: 'Sleeping',
              9: 'Commuting',
              17: 'Working',
              18: 'Commuting',
              20: 'Eating',
              22: 'Resting' }

time_now = localtime()
hour = time_now.tm_hour

for activity_time in sorted(activities.keys()):
   if hour < activity_time:
      print (activities[activity_time])
      break
else:
   print ('Unknown, AFK or sleeping!')


これも、10行ではないですが、activities という辞書を定義するときに、
インデントして継続行になっているところを1行と数えると10行です。

もう長くなったので、
丸ごとファイルに入れて、先頭行に #!/usr/bin/python3 を付加して、chmod u+x で実行可能にします。
そのファイル名を、prog-010.py とすると実行結果はこうなります。
先にdate コマンドを使ったのは、時間を扱うプログラム?だから現在の時間を知るためです。

$ date
2024年 4月 28日 日曜日 07:11:05 JST
$ ./prog-010.py
Sleeping
$

実行時刻を替えてもう一つ実行結果を記録しておきます。

$ date
2024年 4月 29日 月曜日 22:20:34 JST
$ ./prog-010.py
Unknown, AFK or sleeping!
$

さっそくプログラムの中身を見てみましょう。

まず from ですが、
https://docs.python.org/ja/3/reference/simple_stmts.html#import
で、import文の一つの形式として説明されています。

「from 節で指定されたモジュールを見付け出し、必要であればロードし初期化する;
import 節で指定されたそれぞれの識別子に対し以下の処理を行う:」


要するに、

from foo(モジュール名とします) import attr(識別子とします。)

によって、 foo.attr を省略して attr として表せるという指定ですね。

from節でロードするモジュール time は「時刻に関するさまざまな関数を提供」するものですね。
https://docs.python.org/ja/3/library/time.html?highlight=time

これによって、time.localtime() を省略して localtime() として使えて、
「エポックからの経過時間で表現された時刻を、」「ローカル時間に変換します。」
なので、現在の時刻が得られるようです。早速試して見ましょう。

>>> from time import localtime
>>> c = localtime()
>>> c # localtime()の出力(戻り値)
time.struct_time(tm_year=2024, tm_mon=5, tm_mday=2, tm_hour=23, tm_min=42, tm_sec=41, tm_wday=3, tm_yday=123, tm_isdst=0)
>>>
>>> c.tm_hour   # c から tm_hour の値を得る
23
>>> c.tm_year   # c から tm_year の値を得る
2024
>>> c.tm_year + 3  # c.tm_year の値は 文字列ではなくて数値
2027
>>> localtime().tm_hour  # 8時になって localtime() を使うと 8 になっている。
8
>>>

というわけで、プログラムの hour は今の時刻を数値で表したものです。
辞書 activities の キーはこの時刻を表しているのですね。キーが24時間表記なので hour も0 ~ 23 ですね。
ここで、辞書に対する keys() メソッドを調べてみましょう。

>>> a = {5: 'test5', 2: 'test2', 9: 'test9' }  # 辞書 a を定義
>>> a          # a を表示する。
{9: 'test9', 2: 'test2', 5: 'test5'}
>>> a.keys()        # a.keys() を表示する。
dict_keys([9, 2, 5])
>>> sorted(a.keys())    # これをソートする。
[2, 5, 9]
>>>

dict_keys() を sorted()の引数として渡すと、キーのソートされた配列が得られることが分かりました。

つまり、for文で activity_time にソートされたキーから生成された配列から一つづつキーを代入して、ループするのですね。

10番目のプログラムで再び条件式がでてきました。といっても、他のプログラムとほぼ同じだと思うので、
if 文の中の条件式は、hour(現在の時刻) が activity_time より小さかったら 真 となって、
下にインデントされた部分を実行するのですね。
真なら print()で辞書からそのキーに対応する値を表示したあと、break がでてきました。
https://docs.python.org/ja/3/reference/simple_stmts.html#the-break-statement

「break 文は、文を囲う最も内側のループを終了させ、ループにオプションの else 節がある場合にはそれをスキップします。」

なので、
for ループを終了して、その activity_time は保持されるわけですね。

さて、for ループの後ろに インデントのない else: が出てくるのは何でしょうか。
それが、プログラムの説明にある for..else だと思います。
https://docs.python.org/ja/3/reference/compound_stmts.html#the-for-statement
の定義では、
for target_list in expression_list : suite [ else : suite ]
となっているので、
for ループには else: 節を付けることができて、今までは省略されたいたということが分かりました。Python 以外はあまりでてこない?形式です。

「その後、スイートが実行されます。 全ての要素を使い切ったとき (シーケンスが空であったり、イテレータが StopIteration 例外を送出したときは、即座に)、 else 節があればそれが実行され、ループは終了します。」
「最初のスイートの中で break 文が実行されると、 else 節のスイートを実行することなくループを終了します。 」


なので、break 文を使っているので else節をスキップしてループを終了するのですね。

条件を満たさず、すべての要素を使い切ると for ループが終了して、最後にelse節が実行されるわけです。
試してみます。

>>> a
{9: 'test9', 2: 'test2', 5: 'test5'}
>>> for i in sorted(a.keys()):
...       if i > 4 :
...         print(a[i])
... else:
...       print('Finish!')
...
test5
test9
Finish!
>>>
for文の中にbreke文がないのですべてのキーを調べたあとに else: 節を実行しています。

>>> for i in sorted(a.keys()):
...       if 6 < i:
...         print(a[i])
...         break
... else:
...       print('Finish!')
...
test9
>>>
サンプルプログラムのように break文を入れると else: 節はスキップしているのが分かります。

>>> for i in sorted(a.keys()):
...       if 100 < i:
...         print(a[i])
...         break
... else:
...       print('Finish!')
...
Finish!
>>>

該当するキーがないと、ループの中はなにもせずに else: 節を実行するのがわかります。
通常のプログラミング言語では else:節がないので、for ループで break してもfor ループの次の行を実行します。

Python では、 for文の else:節は break と併用すると便利と覚えておきます。
コメント (3)
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする