29
28

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

PythonにおけるString→Bool値の変換 一考

Last updated at Posted at 2014-04-10

事の発端

"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さんのコメントを参考にしました。ありがとうございます。

おわりに

  • 他に良い方法があったらコメントへお願いします。
29
28
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
29
28

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?