事の発端
"false"というString値をFalseというBool値に変換したいけど、良い方法は無いか?
もうちょっと踏み込んで言うと、 C# における Boolean.Parse のようなものは無いか?ということ。
現段階での結論
後述する distutils.util.strtobool() + bool() が落としどころかな。
以前の結論1
その前に考えていたのは、これ。
def CBool( value ):
if isinstance( value, str ) and value.lower() == "false":
return False
return bool( value )
$ python
Python 2.6.6 (r266:84292, Jan 22 2014, 09:42:36)
[GCC 4.4.7 20120313 (Red Hat 4.4.7-4)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> def CBool( value ):
... if isinstance( value, str ) and value.lower() == "false":
... return False
... return bool( value )
...
>>> CBool( "False" )
False
>>> CBool( "false" )
False
>>> CBool( 0 )
False
>>> CBool( [] )
False
>>> CBool( "" )
False
>>> CBool( "True" )
True
>>> CBool( 1 )
True
>>> CBool( [ "hoge" ] )
True
>>> CBool( "hoge" )
True
試行
bool() 組み込み関数
これだと、「事の発端」に挙げた問題は解消できない。
Python 2.6の公式ドキュメント 5. 組み込み型 > 5.1. 真理値テストによると、次の値に該当する場合がFalse、そうでない場合はTrueとなる。
None
False
- 数値型におけるゼロ。例えば
0
,0L
,0.0
,0j
。 - 空のシーケンス型。例えば
''
,()
,[]
。 - 空のマッピング型。例えば
{}
。 -
__nonzero__
または__len__
メソッドが定義されているようなユーザ定義クラスのインスタンスで、それらのメソッドが整数値ゼロまたはbool
値のFalse
を返すとき。
$ python
Python 2.6.6 (r266:84292, Jan 22 2014, 09:42:36)
[GCC 4.4.7 20120313 (Red Hat 4.4.7-4)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> bool( "False" )
True
json.loads()
「事の発端」は解消できるけど、json.loads()本来の使い方と違うので、他の人が読んだら意図がわかりづらくなりかねない。
また、JSONの値が入る前提なので、全て小文字の"false"ではないと通らない。"False"にするとValueErrorとなる。
$ python
Python 2.6.6 (r266:84292, Jan 22 2014, 09:42:36)
[GCC 4.4.7 20120313 (Red Hat 4.4.7-4)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import json
>>> json.loads( "false" )
False
>>> json.loads( "False" )
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib64/python2.6/json/__init__.py", line 307, in loads
return _default_decoder.decode(s)
File "/usr/lib64/python2.6/json/decoder.py", line 319, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File "/usr/lib64/python2.6/json/decoder.py", line 338, in raw_decode
raise ValueError("No JSON object could be decoded")
ValueError: No JSON object could be decoded
ast モジュールを使う
これも「事の発端」は解消できる。また、ast.literal_eval()は、単なるeval()と違い変換はリテラル値に絞られているので、どこの骨かもわからない変数をパースするときにでもリスクが低いのもポイント。ただし、"false"はパースできない。
$ python
Python 2.6.6 (r266:84292, Jan 22 2014, 09:42:36)
[GCC 4.4.7 20120313 (Red Hat 4.4.7-4)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import ast
>>> ast.literal_eval( "False" )
False
>>> ast.literal_eval( "false" )
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib64/python2.6/ast.py", line 68, in literal_eval
return _convert(node_or_string)
File "/usr/lib64/python2.6/ast.py", line 67, in _convert
raise ValueError('malformed string')
ValueError: malformed string
※ @everesさんのコメントを参考にしました。ありがとうございます。
文字列を評価
これも「事の発端」は解消できる。意図もわかりやすい。大文字・小文字の差も吸収できる。ただ、メソッド化してどこかにまとめておいた方が良さそう。ただし、変数に文字列以外が入ってくるとエラーになってしまう。
$ python
Python 2.6.6 (r266:84292, Jan 22 2014, 09:42:36)
[GCC 4.4.7 20120313 (Red Hat 4.4.7-4)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> False if "False".lower() == "false" else True
False
>>> False if "false".lower() == "false" else True
False
>>> False if "True".lower() == "false" else True
True
※ @key3さんのコメントを参考にしました。ありがとうございます。
distutils.util.strtobool を使う
これも「事の発端」は解消できる。意図もわかりやすい。また、True / Falseの意図を持った文字列も良きに計らってくれる。ただ、変換対象ではない文字列が入ると例外が出るので、ちゃんと拾うこと。
$ python
Python 2.6.6 (r266:84292, Jan 22 2014, 09:42:36)
[GCC 4.4.7 20120313 (Red Hat 4.4.7-4)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import distutils.util
>>> distutils.util.strtobool( "False" )
0
>>> distutils.util.strtobool( "false" )
0
>>> bool( distutils.util.strtobool( "False" ) )
False
>>> bool( distutils.util.strtobool( "No" ) )
False
>>> distutils.util.strtobool( "True" )
1
>>> bool( distutils.util.strtobool( "True" ) )
True
>>> bool( distutils.util.strtobool( "" ) )
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib64/python2.6/distutils/util.py", line 424, in strtobool
raise ValueError, "invalid truth value %r" % (val,)
ValueError: invalid truth value ''
※ @indigo13loveさんのコメントを参考にしました。ありがとうございます。
おわりに
- 他に良い方法があったらコメントへお願いします。