Python は 1 == ‘1’ が False になる
はじめに
先日、次のようなコードを書いたところ思った通りに動きませんでした。
from_db # 1 のような整数値が入る
user_post_data # '1' のような文字列型の数値が入る
if from_db == user_post_data:
(処理内容)
整数でも文字でも、勝手に Python が変換して比較してくれると思っていたのですが、 型が違うと False となってしまいました。
ちなみに、この二つは print 関数に渡すと全く同じ出力結果になります。 これが余計に分かりづらくしています。
from_db = 1
user_post_data = '1'
print(from_db)
print(user_post_data)
bash-3.2$ python test.py
1
1
これは(一番単純な方法だと)、以下のように書き換えることで正しく動きます。
from_db # 1 のような整数値が入る
user_post_data # '1' のような文字列型の数値が入る
if from_db == int(user_post_data): # int にキャストする
(処理内容)
Python は型を宣言が必要ない言語なのですが、ちゃんと型の比較をしているようです
入門書をぱらぱらと読んで分かったつもりになっていましたが、もしかしたらこのような勘違いがあるのではと思い Phthon の比較周りについて、他の言語と比べつつまとめてみました。
あんまり分かっていない自分なりにまとめたものですので、 よくご存知の方にとっては当たりまえの内容になると思いますが。。。
環境
bash-3.2$ python -V
Python 3.5.2
bash-3.2$ php -v
PHP 5.5.36 (cli) (built: May 29 2016 01:07:06)
Copyright (c) 1997-2015 The PHP Group
Zend Engine v2.5.0, Copyright (c) 1998-2015 Zend Technologies
bash-3.2$ node -v
v6.2.2
なぜか PHP7 ではなく PHP5 がインストールされてました。
他の言語との比較
Python は変数を作る際に型の宣言を行いません。 また、変数の型は実行時に自動的に変わります。
a = 10
a = 'abc' # 数値に文字列を代入しても動く
内部ではちゃんと型を持っています
a = 10
print(type(a)) #=> <class 'int'>
a = 'abc'
print(type(a)) #=> <class 'str'>
これは、多くのスクリプト言語でも同じ事が言えます。 (私が辛うじて書くことの出来る、)JavaScript と PHP も型宣言はありません。
しかしながら、この二つの言語とPythonには違いがあります。 これらでは、私が最初にあげたようなコードがこちらの想定通りに動いてくれます。
JavaScript:
var a = 1;
var b = '1';
if (a == b) {
console.log("True"); #=> True
} else {
console.log("False");
}
PHP:
<?php
$a = 1;
$b = '1';
if ($a == $b) {
echo('True'); #=> True
} else {
echo('False');
}
?>
JavaScript や PHP は、型が違っても緩く比較しています。 一定の規則で型を変換して比較を行っているのです。 PHPの公式マニュアルには代表的な変換例が掲載されています。
これは便利ですが、思いも寄らぬ結果を招くことがあります。 例えば、 PHP で以下のように書くと、空文字を検知しようとして余計な物まで検知してしまいます
<?php
$user_input = '0'; # あるユーザが 0 とだけ入力した
if (!$user_input) {
echo("ERROR: 内容が入力されていません\n"); #=> これが出力されてしまう
}
?>
そのため、この二つには厳密に型を比較する演算子(===)が用意されています。
JavaScript:
var a = 1;
var b = '1';
console.log("Loose:");
if (a == b) {
console.log("True"); #=> True
} else {
console.log("False");
}
console.log("Strict:");
if (a === b) {
console.log("True");
} else {
console.log("False"); #=> False
}
PHP:
<?php
$a = 1;
$b = '1';
echo('Loose: ');
if ($a == $b) {
echo('True'); #=> True
} else {
echo('False');
}
echo("\n");
if ($a === $b) {
echo('True');
} else {
echo('False'); #=> False
}
echo("\n");
?>
ちなみに、Python にはこんな演算子はありません
a = 1
b = '1'
if a === b:
print('True')
else:
print('False')
bash-3.2$ python test.py
File "test.py", line 4
if a === b:
^
SyntaxError: invalid syntax
ここまでのまとめ
- Python は他のスクリプト言語に漏れず、動的型付き言語
- つまり、変数を作ったり使ったりする際に型を意識する必要はそんなにない
- だが、比較の際は型を厳格に区別して比較している
- 一方、JavaScript や PHP は異なる型での比較が緩い
- 他と比べると、Python のコードって短い
Python における False とは
さっきの PHP の例を Python で実行してみました。
a = '0'
if not a:
print('ERROR!')
bash-3.2$ python test.py
bash-3.2$
なにも出力されませんでした。
そもそも、空文字は検知してくれるのでしょうか?
a = ''
if not a:
print('ERROR!')
bash-3.2$ python test.py
ERROR!
ちゃんとエラーメッセージを出してくれました。 空文字は False になるようです。
では、False となるのはどの様な時なのでしょうか? 先輩からお借りしている入門Python3で、「4.3.1 True とは何か」という節で詳しく述べられていました。 実際に、そこに書かれている物や他の言語だと False になっているものを並べて検証してみました。
a = ''
b = []
c = {}
d = 0
e = set()
f = "False"
g = -1
h = '0'
if a:
print('True')
else:
print('False')
if b:
print('True')
else:
print('False')
if c:
print('True')
else:
print('False')
if d:
print('True')
else:
print('False')
if e:
print('True')
else:
print('False')
if f:
print('True')
else:
print('False')
if g:
print('True')
else:
print('False')
if h:
print('True')
else:
print('False')
bash-3.2$ python test.py
False
False
False
False
False
True
True
True
数値の 0 が False になるのが恐いですね。 うっかり使って、想定外の動きをされそうです。
ちなみに、PHP だとこうなります。
<?php
$a = '';
$b = [];
$c = null;
$d = 0;
$e = array();
$f = "FALSE";
$g = -1;
$h = '0';
if ($a) {
print("TRUE\n");
} else {
print("FALSE\n");
}
if ($b) {
print("TRUE\n");
} else {
print("FALSE\n");
}
if ($d) {
print("TRUE\n");
} else {
print("FALSE\n");
}
if ($e) {
print("TRUE\n");
} else {
print("FALSE\n");
}
if ($f) {
print("TRUE\n");
} else {
print("FALSE\n");
}
if ($g) {
print("TRUE\n");
} else {
print("FALSE\n");
}
if ($h) {
print("TRUE\n");
} else {
print("FALSE\n");
}
?>
bash-3.2$ php test.php
FALSE
FALSE
FALSE
FALSE
TRUE
TRUE
FALSE
意外と同じでした。
Python で「何もない」を表すには、=== ではなく is 演算子を用いるようです。 これで、「空っぽ」なのか「そもそもない」のかを区別して記述します。
a = ''
b = []
c = None
d = 0
e = set()
f = "False"
g = -1
h = '0'
if a is None:
print('True')
else:
print('False')
if b is None:
print('True')
else:
print('False')
if c is None:
print('True')
else:
print('False')
if d is None:
print('True')
else:
print('False')
if e is None:
print('True')
else:
print('False')
if f is None:
print('True')
else:
print('False')
if g is None:
print('True')
else:
print('False')
if h is None:
print('True')
else:
print('False')
bash-3.2$ python test.py
False
False
True
False
False
False
False
False
これで、None 以外の全て物を弾くことができました。
ここまでのまとめ
- Python も False との比較は暗黙的なキャストが行われる
- 値の有無を確かめるには if val is None / if val is not None を用いる
まとめ
- Python は他のスクリプト言語に漏れず、動的型付き言語
- つまり、変数を作ったり使ったりする際に型を意識する必要はそんなにない
- だが、比較の際は型を厳格に区別して比較している
- 一方、JavaScript や PHP は異なる型での比較が緩い
- Python も False との比較は暗黙的なキャストが行われる
- 値の有無を確かめるには if val is None / if val is not None を用いる
- 何が「等しい」かは言語によって結構異なる
- 初めての言語ではちゃんと調べて使う
江藤 光
まだまだ気持ちは新人です。