web-dev-qa-db-ja.com

ブール値には2つの可能な値があります。 3つの可能な値を持つタイプはありますか?

重複の可能性:
Pythonで「列挙型」を実装する最良の方法は何ですか?

「はい」、「いいえ」、「わからない」の3つの状態の1つを返すのが理想的な関数を書いています。

  1. プログラミング言語には、3つの状態を持つ型があり、状態は3つだけですか?ブール値のようですが、2つの状態ではなく3つの状態がありますか?

  2. このような型がない言語(Pythonなど)では、これを表すのに最適な型は何ですか?

    現在は整数(0「いいえ」の場合、1「わからない」および2「はい」の場合)、しかしもっと良い方法があるでしょうか?整数は少し「マジックナンバー」のようです。

    TrueFalseまたはNoneを返すことができますが、Noneはほとんどの比較コンテキストでFalseと評価されるため、少し熟しているようですエラーの場合。

38
Paul D. Waite

Pythonでは、これらの3つの値のいずれかを保持するラッパーオブジェクトを使用してそれを行います。TrueFalse、およびNoneを使用します。ブールのようなオブジェクトの暗黙的な真偽値考えられる3つの値には問題があるため、それを完全に禁止することで解決します__nonzero__()で例外を発生させるか、 Python 3、__bool__())したがって、in==、または!=を使用して、比較を常に明示的に行う必要があります。特定のシングルトンのみが一致するように、同一性をIDとして実装します値TrueFalse、および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つの値は、単一の値の!=の反対です)。これらのオブジェクトで実行できる他の論理演算がある場合は、これらをメソッドとして実装するか、特定の演算子をオーバーライドすることで実装できます(ただし、論理notand、およびorはオーバーライドできませんが、- 提案 追加します)。

また、Pythonではid()をオーバーライドできないので、注意してください。 Tristate(None) is NoneFalseです。 2つのオブジェクトは実際には異なります。シングルトンと比較する場合、良いPythonスタイルはisを使用することなので、これは残念ですが避けられません。

Edit 4/27/16:あるTristateオブジェクトを別のオブジェクトと比較するためのサポートを追加しました。

35
kindall

これは Ternary logic またはThree-valued Logicと呼ばれます。他の回答が示唆するように、クラスを実装することもできます:

class Ternary:
    FALSE = 0
    TRUE = 1
    UNKNOWN = 2

私自身、おそらくあなたの解決策(TrueFalseNone)に行くでしょうが、私はあなたの懸念を理解しています。

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を疑似シングルトンにすることができなくなるという欠点があります。

6
Silas Ray
  1. 少なくとも1つの言語にこれがあります: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_type
  2. Pythonはわかりませんが、好みによって異なります。使いやすさ(enumまたはclass)と効率(4ビットフィールド)
3
Tar

これは、その名前のC構文にちなんで、一般的に「列挙型」として知られています。

独自のクラスを簡単に作成できます。そのオブジェクトは、セットの値で初期化する必要があり、それに応じて適切な比較、等価、および真理関数を作成できます。

2
Marcin

dbf module に3値の論理クラスがあります。

False/True/Unknownをシングルトン値Falsth/Truth/Unknownとして実装します。すべての比較演算子を実装し、PythonシングルトンFalse/True/NoneNoneは不明を意味するものと見なされます)との比較も可能にします。Unknown値との比較はUnknownとなり、試行されますUnknownおよびifはブールコンテキストで使用でき、boolは直接比較できますが、TypeErrorステートメント(または他のTruthコンテキスト)でFalsth値を暗黙的に使用するとUnknownが発生します。

andor、および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."
1
Ethan Furman

そのような組み込み型はありません。また、列挙型も型としてサポートされていません。ただし、次のように定数を使用できます。

class Option:
    NO = 0
    DONT_KNOW = 1
    YES = 2

reply = Option.YES
0

私はPythonプログラミングではありませんが、わからないの場合はNoneを返すことができます。呼び出し元「はい」、「いいえ」、「なし」を確認する必要がありますが、少なくとも彼らはあなたが知らないことを知っています。

http://boodebr.org/main/python/tourist/none-empty-nothing

0
Ninju Bohra

2つ以上の値を持つbooleanに似たタイプを見たことがありません。結局のところ、「ブール値」とは、関数が「ブール値のドメイン」に対して機能することを意味します。「ブール値のドメイン」には、正確に2つの値があります。

とはいえ、整数、列挙型、または文字列を使用しても問題ありません。 pythonでは、変数YES、NO、MAYBEのみを含むモジュールを作成し、そこから他のすべての場所にインポートできます。

0
Ecir Hana