重複の可能性:
Pythonで「列挙型」を実装する最良の方法は何ですか?
「はい」、「いいえ」、「わからない」の3つの状態の1つを返すのが理想的な関数を書いています。
プログラミング言語には、3つの状態を持つ型があり、状態は3つだけですか?ブール値のようですが、2つの状態ではなく3つの状態がありますか?
このような型がない言語(Pythonなど)では、これを表すのに最適な型は何ですか?
現在は整数(0
「いいえ」の場合、1
「わからない」および2
「はい」の場合)、しかしもっと良い方法があるでしょうか?整数は少し「マジックナンバー」のようです。
True
、False
またはNone
を返すことができますが、None
はほとんどの比較コンテキストでFalse
と評価されるため、少し熟しているようですエラーの場合。
Pythonでは、これらの3つの値のいずれかを保持するラッパーオブジェクトを使用してそれを行います。True
、False
、およびNone
を使用します。ブールのようなオブジェクトの暗黙的な真偽値考えられる3つの値には問題があるため、それを完全に禁止することで解決します(__nonzero__()
で例外を発生させるか、 Python 3、__bool__()
)したがって、in
、==
、または!=
を使用して、比較を常に明示的に行う必要があります。特定のシングルトンのみが一致するように、同一性をIDとして実装します値True
、False
、およびNone
が一致します。
class Tristate(object):
def __init__(self, value=None):
if any(value is v for v in (True, False, None)):
self.value = value
else:
raise ValueError("Tristate value must be True, False, or None")
def __eq__(self, other):
return (self.value is other.value if isinstance(other, Tristate)
else self.value is other)
def __ne__(self, other):
return not self == other
def __nonzero__(self): # Python 3: __bool__()
raise TypeError("Tristate object may not be used as a Boolean")
def __str__(self):
return str(self.value)
def __repr__(self):
return "Tristate(%s)" % self.value
使用法:
t = Tristate(True)
t == True # True
t != False # True
t in (True, False) # True
bool(t) # Exception!
if t: print "woo" # Exception!
Tristate
オブジェクトを使用する場合、どの値を一致させるかを明示的に指定する必要があります(つまり、foo == True or bar != None
)。 foo in (False, None)
を実行して複数の値を照合することもできます(もちろん、in
の2つの値は、単一の値の!=
の反対です)。これらのオブジェクトで実行できる他の論理演算がある場合は、これらをメソッドとして実装するか、特定の演算子をオーバーライドすることで実装できます(ただし、論理not
、and
、およびor
はオーバーライドできませんが、- 提案 追加します)。
また、Pythonではid()
をオーバーライドできないので、注意してください。 Tristate(None) is None
はFalse
です。 2つのオブジェクトは実際には異なります。シングルトンと比較する場合、良いPythonスタイルはis
を使用することなので、これは残念ですが避けられません。
Edit 4/27/16:あるTristate
オブジェクトを別のオブジェクトと比較するためのサポートを追加しました。
これは Ternary logic またはThree-valued Logicと呼ばれます。他の回答が示唆するように、クラスを実装することもできます:
class Ternary:
FALSE = 0
TRUE = 1
UNKNOWN = 2
私自身、おそらくあなたの解決策(True
、False
、None
)に行くでしょうが、私はあなたの懸念を理解しています。
None = 2、true = 1、unknown = 2の場合、None問題と同じです(unknownも実際にはtrueではありませんが、注意しないとTrueに評価されます)。
私は、少なくともあなたが望むものに近いものを手に入れるためのハックな方法を思いついたと思います。少なくとも、if/elseやその他のブールevalインスタンスで3値方式で評価されるものを取得します。
class Yes(object):
def __nonzero__(self):
return True
class No(object):
def __nonzero__(self):
return False
class Unknown(object):
def __nonzero__(self):
raise ValueError('Unknown typed values do not evaluate to True/False. Try using Ternary.eval().')
class Ternary(object):
def __init__(self, yes, no, unknown):
setattr(self, yes, Yes())
setattr(self, no, No())
setattr(self, unknown, Unknown())
@staticmethod
def eval(value, unknown_eval):
if isinstance(value, Unknown):
return unknown_eval
return bool(value)
使用法:
t = Ternary('yes', 'no', 'unknown')
# Do stuff to assign ternary value to x
if Ternary.eval(x, True):
print 'x is yes or unknown'
if Ternary.eval(x, False):
print 'x is yes only'
はい、いいえ、不明の疑似シングルトンを作成して、evalを少し洗練させることができます。値が「はい」または「いいえ」になることがわかっている場合は、単純なifチェックを実行できますが、Unknownで直接bool()(つまり、x)を実行しようとすると、TypeErrorが発生します。これによりコードがより明確になりますが、3項タイプの値をチェックするたびに、その条件のコンテキストでunknownをどのように処理するかをコードで定義する必要があるため、プラスになります。 。
編集:特別な処理はそれほど必要ないが柔軟性が低い代替案を考えました。したがって、上記のように変更します。
class Unknown(object):
def __init__(self, eval):
self._eval = eval
def __nonzero__(self):
return self._eval
class Ternary(object):
def __init__(self, yes, no, unknown, unknown_eval):
setattr(self, yes, Yes())
setattr(self, no, No())
setattr(self, unknown, Unknown(unknown_eval))
使用法:
t1 = Ternary('yes', 'no', 'unknown', True)
t2 = Ternary('yes', 'no', 'unknown', False)
# Do stuff to assign ternary values to x1 and x2
if x1:
print 'x is yes or unknown'
if x2:
print 'x is yes only'
これには、unknownでゼロ以外がspecの呼び出しとして機能するという利点がありますが、unknownのevalがインスタンス化によって確定され、Unknownを疑似シングルトンにすることができなくなるという欠点があります。
C#
:int? num = null;
、現在num
は実際にはNullable<Int32>
(疑問符は「構文上の砂糖」です)参照: http://msdn.Microsoft.com/en-us/library/1t3y8s4s%28v=vs.80%29.aspx および http://en.wikipedia.org/wiki/Nullable_typeenum
またはclass
)と効率(4ビットフィールド)これは、その名前のC構文にちなんで、一般的に「列挙型」として知られています。
独自のクラスを簡単に作成できます。そのオブジェクトは、セットの値で初期化する必要があり、それに応じて適切な比較、等価、および真理関数を作成できます。
dbf module に3値の論理クラスがあります。
False
/True
/Unknown
をシングルトン値Falsth
/Truth
/Unknown
として実装します。すべての比較演算子を実装し、PythonシングルトンFalse
/True
/None
(None
は不明を意味するものと見なされます)との比較も可能にします。Unknown
値との比較はUnknown
となり、試行されますUnknown
およびif
はブールコンテキストで使用でき、bool
は直接比較できますが、TypeError
ステートメント(または他のTruth
コンテキスト)でFalsth
値を暗黙的に使用するとUnknown
が発生します。
and
、or
、およびnot
の動作をオーバーライドすることはできないため、型はビット演算子&
、|
、および~
をオーバーライドします。
また、Unknown
が__index__
の値を持つ2
も実装します。
例:
from dbf import Logical, Truth, Falsth, Unknown
middle_name = raw_input("What is the middle name? ['?' if unknown] ").strip()
if middle_name == '?':
middle_name = ''
middle_exists = Unknown
Elif middle_name:
middle_exists = Truth
else:
middle_exists = Falsth
.
.
.
if middle_exists is Unknown:
print "The middle name is unknown."
Elif middle_exists:
print "The middle name is %s." % middle_name
else:
print "This person does not have a middle name."
そのような組み込み型はありません。また、列挙型も型としてサポートされていません。ただし、次のように定数を使用できます。
class Option:
NO = 0
DONT_KNOW = 1
YES = 2
reply = Option.YES
私はPythonプログラミングではありませんが、わからないの場合はNoneを返すことができます。呼び出し元「はい」、「いいえ」、「なし」を確認する必要がありますが、少なくとも彼らはあなたが知らないことを知っています。
2つ以上の値を持つbooleanに似たタイプを見たことがありません。結局のところ、「ブール値」とは、関数が「ブール値のドメイン」に対して機能することを意味します。「ブール値のドメイン」には、正確に2つの値があります。
とはいえ、整数、列挙型、または文字列を使用しても問題ありません。 pythonでは、変数YES、NO、MAYBEのみを含むモジュールを作成し、そこから他のすべての場所にインポートできます。