1: 2019-05-26 (日) 19:35:44 njf |
現: 2019-05-26 (日) 23:34:44 njf |
| *Flag [#h3172853] | | *Flag [#h3172853] |
| | | |
- | 注意:FlagやIntFlagは列挙型Enumの一種です。Enumを知らない場合は[[Python/列挙型]]を先に読むのを推奨します。 | + | ''注意'':FlagやIntFlagは列挙型Enumの一種です。Enumを知らない場合は[[Python/列挙型]]を先に読むのを推奨します。 |
| | | |
| 昔からあるプログラムの書き方で、ビット毎にフラグを設定して一つの変数に複数のフラグを保存する方法があります。 | | 昔からあるプログラムの書き方で、ビット毎にフラグを設定して一つの変数に複数のフラグを保存する方法があります。 |
| ビット単位で管理するのでメモリが節約できます。また一般にビット演算は高速なのでプログラムの高速化も狙えます。 | | ビット単位で管理するのでメモリが節約できます。また一般にビット演算は高速なのでプログラムの高速化も狙えます。 |
| | | |
- | これと同じようなことを実現するのPythonのクラスがFlagです。 | + | これと同じようなことを実現するPythonのクラスがFlagです。 |
| | | |
| 例えば、ゲームで状態異常を定義したいとして、次のようなクラスを定義します。 | | 例えば、ゲームで状態異常を定義したいとして、次のようなクラスを定義します。 |
| | | |
| from enum import Flag | | from enum import Flag |
| + | |
| class PlayerStatus(Flag): | | class PlayerStatus(Flag): |
| SLEEP = 1 #睡眠 | | SLEEP = 1 #睡眠 |
| | | |
| from enum import Flag ,auto | | from enum import Flag ,auto |
| + | |
| class PlayerStatus(Flag): | | class PlayerStatus(Flag): |
| SLEEP = auto() | | SLEEP = auto() |
| POISON = auto() | | POISON = auto() |
| PARALYSIS = auto() | | PARALYSIS = auto() |
| + | |
| for s in PlayerStatus: | | for s in PlayerStatus: |
| print(s.name,s.value) | | print(s.name,s.value) |
| PlayerStatus.POISON|SLEEP | | PlayerStatus.POISON|SLEEP |
| | | |
- | というふうに、フラグの状態をわかりやすく出してくれるのでデバッグの時便利です。 | + | というふうに、実際にフラグが複数設定されています。 |
| + | また、Flag型はフラグの状態をわかりやすく出力してくれるのでデバッグの時便利です。 |
| | | |
| フラグが立っているかどうかは「&」でチェックします。 | | フラグが立っているかどうかは「&」でチェックします。 |
| | | |
| status = PlayerStatus.SLEEP | PlayerStatus.POISON | | status = PlayerStatus.SLEEP | PlayerStatus.POISON |
| + | |
| if status & PlayerStatus.SLEEP: | | if status & PlayerStatus.SLEEP: |
| print("SLEEP!") | | print("SLEEP!") |
| + | |
| if status & PlayerStatus.POISON: | | if status & PlayerStatus.POISON: |
| print("POISON!") | | print("POISON!") |
| + | |
| if status & PlayerStatus.PARALYSIS: | | if status & PlayerStatus.PARALYSIS: |
| print("PARALYSIS!") | | print("PARALYSIS!") |
| POISON! | | POISON! |
| | | |
- | フラグをオフにするには排他的論理和「^」を使います。 | + | フラグをオフにするには以下のように「&」と「~」(否定)を組み合わせます。 |
| | | |
| status = PlayerStatus.SLEEP | PlayerStatus.POISON | | status = PlayerStatus.SLEEP | PlayerStatus.POISON |
- | | + | |
- | status = status ^ PlayerStatus.SLEEP | + | status = PlayerStatus.SLEEP & (~PlayerStatus.POISON) |
| + | |
| if status & PlayerStatus.SLEEP: | | if status & PlayerStatus.SLEEP: |
| print("SLEEP!") | | print("SLEEP!") |
| + | |
| if status & PlayerStatus.POISON: | | if status & PlayerStatus.POISON: |
| print("POISON!") | | print("POISON!") |
| + | |
| if status & PlayerStatus.PARALYSIS: | | if status & PlayerStatus.PARALYSIS: |
| print("PARALYSIS!") | | print("PARALYSIS!") |
| 結果: | | 結果: |
| POISON! | | POISON! |
- | | |
- | フラグをオフにするには以下のように「&」と「~」(否定)を組み合わせる方法も良く行われます。 | |
- | | |
- | status = PlayerStatus.SLEEP & (~PlayerStatus.POISON) | |
| | | |
| また、Flag型はFlag型同士でなければ演算できないことに注意してください。 | | また、Flag型はFlag型同士でなければ演算できないことに注意してください。 |
| | | |
| status = PlayerStatus.SLEEP | 2 | | status = PlayerStatus.SLEEP | 2 |
| + | |
| print(status) | | print(status) |
| | | |
| フラグがたくさんあって整理が難しい場合や、少しでも処理を高速化したい場合には便利なクラスです。 | | フラグがたくさんあって整理が難しい場合や、少しでも処理を高速化したい場合には便利なクラスです。 |
| | | |
- | ただし、現在のようにメモリも大容量でCPUも速くなった時代にフラグ処理が少し軽くなる程度の工夫が必要かどうかはちょっと微妙な気もします。 | + | ただし、現在のようにメモリも大容量でCPUも速くなった時代にフラグ処理が少し軽くなる程度の工夫が必要かどうかはちょっと微妙な気もします。特にPythonのようなスクリプト言語は他の部分が遅いのでフラグがボトルネックにはなりにくく、ビットフラグをよく使うのはCなどのコンパイル言語というイメージです。そういった言語で使い慣れている人にはFlagやIntFlagは使いやすいでしょう。 |
| | | |
- | フラグが少ない場合は真偽型boolを使う方が楽です。 | + | フラグが少なく処理が簡単な場合は真偽型boolをそのまま使うか、いくつかまとめたクラスを作って使う方が楽です。 |