Ad

Flag anchor.png Edit

注意:FlagやIntFlag編集は列挙型Enumの一種です。Enumを知らない場合はPython​/列挙型を先に読むのを推奨します。

昔からあるプログラムの書き方で、ビット毎にフラグを設定して一つの変数に複数のフラグを保存する方法があります。

ビット単位で管理するのでメモリが節約できます。また一般にビット演算は高速なのでプログラムの高速化も狙えます。

これと同じようなことを実現するPythonのクラスがFlagです。

例えば、ゲームで状態異常を定義したいとして、次のようなクラスを定義します。

from enum import Flag

class PlayerStatus(Flag):
    SLEEP = 1 #睡眠
    POISON = 2 #毒
    PARALYSIS = 4 #麻痺

ここで1,2,4は二進数で書けば1,10,100の事で、それぞれ1ビット目、2ビット目,3ビット目をフラグとして使っています。

このように手で書くこともできますが、Python3.6で追加されたautoという関数を使うと自動で二のべき乗を割り振ってくれます。

from enum import Flag ,auto

class PlayerStatus(Flag):
    SLEEP = auto()
    POISON = auto()
    PARALYSIS = auto()

for s in PlayerStatus:
    print(s.name,s.value)

結果:

SLEEP 1
POISON 2
PARALYSIS 4

これの良いところは一つの変数に複数のフラグを設定できることです。 例えば、睡眠かつ毒状態のステータスは

status = PlayerStatus.SLEEP | PlayerStatus.POISON

と書きます。これを表示させると、

print(status)

結果:

PlayerStatus.POISON|SLEEP

というふうに、実際にフラグが複数設定されています。 また、Flag型はフラグの状態をわかりやすく出力してくれるのでデバッグの時便利です。

フラグが立っているかどうかは「&」でチェックします。

status = PlayerStatus.SLEEP | PlayerStatus.POISON

if status & PlayerStatus.SLEEP:
    print("SLEEP!")

if status & PlayerStatus.POISON:
    print("POISON!")

if status & PlayerStatus.PARALYSIS:
    print("PARALYSIS!")

結果:

SLEEP!
POISON!

フラグをオフにするには以下のように「&」と「~」(否定)を組み合わせます。

status = PlayerStatus.SLEEP | PlayerStatus.POISON

status = PlayerStatus.SLEEP & (~PlayerStatus.POISON)

if status & PlayerStatus.SLEEP:
    print("SLEEP!")

if status & PlayerStatus.POISON:
    print("POISON!")

if status & PlayerStatus.PARALYSIS:
    print("PARALYSIS!")

結果:

POISON!

また、Flag型はFlag型同士でなければ演算できないことに注意してください。 Intと演算したいときには次のIntFlag編集型を使います。

Page Top

IntFlag編集 anchor.png Edit

IntFlag編集型はFlag型とほぼ同じ機能がありますが、Flag型とは異なり整数としても扱えます。

つまり、Flag型では次の処理はエラーとなります。

status = PlayerStatus.SLEEP | 2

print(status)

Flag型での結果:

Traceback (most recent call last):
  File "enumflgs.py", line 50, in <module>
    status = PlayerStatus.SLEEP | 2
TypeError: unsupported operand type(s) for |: 'PlayerStatus' and 'int'

しかし、IntFlag編集型なら問題なく実行されます。

IntFlag編集型での結果:

PlayerStatus.POISON|SLEEP

直接数値が使えないのでFlag型の方がマジックナンバーが発生しにくいという利点があります。

一方でIntFlag編集型は計算結果や外部入力の数値をそのままフラグとして演算できるという利点があります。

基本的にFlag型を使い、フラグを整数と演算する必要がある場合はIntFlag編集型を使うというのが良いかもしれません。

Page Top

まとめ anchor.png Edit

Flagはビット演算でのフラグの管理を使いやすくするクラスです。 IntFlag編集はそのFlagを整数としても扱えるようにした物です。

フラグがたくさんあって整理が難しい場合や、少しでも処理を高速化したい場合には便利なクラスです。

ただし、現在のようにメモリも大容量でCPUも速くなった時代にフラグ処理が少し軽くなる程度の工夫が必要かどうかはちょっと微妙な気もします。特にPythonのようなスクリプト言語は他の部分が遅いのでフラグがボトルネックにはなりにくく、ビットフラグをよく使うのはCなどのコンパイル言語というイメージです。そういった言語で使い慣れている人にはFlagやIntFlag編集は使いやすいでしょう。

フラグが少なく処理が簡単な場合は真偽型boolをそのまま使うか、いくつかまとめたクラスを作って使う方が楽です。


トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード印刷に適した表示   ページ新規作成 全ページ一覧 単語検索 最新ページの一覧   ヘルプ   最新ページのRSS 1.0 最新ページのRSS 2.0 最新ページのRSS Atom Powered by xpWiki
Counter: 3890, today: 2, yesterday: 1
初版日時: 2019-05-26 (日) 19:35:44
最終更新: 2019-05-26 (日) 22:34:44 (JST) (1758d) by njf
MenuBar
広告

ログイン

ユーザー名:


パスワード:





パスワード紛失

Portuguese | English | German | Greek | Japanese | Korean | Russian | T-Chinese top
NJF