Help us understand the problem. What is going on with this article?

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

More than 5 years have passed since last update.

事の発端

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

おわりに

  • 他に良い方法があったらコメントへお願いします。
koemu
※このサイトの掲載内容は私自身の見解であり、必ずしも所属する組織の立場、戦略、意見を代表するものではありません。
http://www.koemu.com/blog/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした