rcmdnk's blog

Python for Data Science For Dummies

Pythonでオブジェクトの比較の時に気をつけることと、 同じような事でJavaのString型の比較の時に気をつけることについて。

Pythonの’==’と’is’

Pythonで2つの物が同値かどうか確認するには ==を使う方法とisを使う方法がありますが、 これらは少し違うものです。

Immutable 1 なintやstring等の場合には基本的に結果は同じです。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
>>> a = 1
>>> if a == 1:
...     print 'Same!'
...
Same!
>>> if a is 1:
...     print 'Same!'
...
Same!
>>> b = 1
>>> if a == b:
...     print 'Same!'
...
Same!
>>> if a is b:
...     print 'Same!'
...
Same!
>>>

一方、Mutableなリストとかだと

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
>>> a = [1, 2, 3]
>>> if a == [1, 2, 3]:
...     print 'Same!'
...
Same!
>>> if a is [1, 2, 3]:
...     print 'Same!'
...
>>> b = [1, 2, 3]
>>> if a == b:
...     print 'Same!'
...
Same!
>>> if a is b:
...     print 'Same!'
...
>>>

の様に、isの方だと同値とみなしません。

これは、==の方は値を比較しているのに対して、 isの方は同じオブジェクト(同じID、メモリ上のアドレスに対応するもの)かどうかを比較してるからです。

実際IDを見てみると、

1
2
3
4
5
6
7
8
9
>>> a = 1
>>> b = 1
>>> print id(a), id(b), id(1)
140595231236200 140595231236200 140595231236200
>>> a = [1, 2, 3]
>>> b = [1, 2, 3]
>>> print id(a), id(b), id([1, 2, 3])
4478530552 4478530624 4478530696
>>>

な感じでint型の方は1なものは全て同じIDですが、 listの方では値が同じでもIDはそれぞれ違っています。

Javaの’==’と’equals’について

Javaの型にはプリミティブ型と呼ばれる基本的な方が有り、 byte, short, int, long, float, double, char, boolean の基本的な型で小文字で始める型です。

これらに関しては==で同値かどうか判断します。

一方、String等はオブジェクトで、 オブジェクトは全てequalsというメソッドを持っています。

このequalsはデフォルトで

1
2
3
public boolean equals(Object obj) {
  return (this == obj);
}

という風に定義されていて、==と同じです。

で、この==は、オブジェクトの参照先が同じものかどうか、でtrue or falseを返します。

なので、String型とかでも、同じ文字列を持つものでも ==で判断すると違うオブジェクトであれば違うものと判断されます。

同じ内容かどうか、を判断するために、 String型ではequalsメソッドをオーバーライドして 文字列の内容が同じかどうか、を返す様にしてあります。

1
2
3
4
5
6
7
8
String s1 = new String("abc");
String s2 = new String("abc");
if(s1 == s2){
  System.out.plingln("s1 == s2");
}
if(s1.equals(s2)){
  System.out.plingln("s1.equals(s2)");
}

とすると

s1.equals(s2)

だけ表示されます。

ただ、次の様にnewを使わずに直接文字列を入れるようにすると

1
2
3
4
5
6
7
8
String s1 = "abc";
String s2 = "abc";
if(s1 == s2){
  System.out.plingln("s1 == s2");
}
if(s1.equals(s2)){
  System.out.plingln("s1.equals(s2)");
}

とすると

s1 == s2
s1.equals(s2)

と両方表示されます。

この場合はインスタンス化されてない文字列が擬似プリミティブ型と呼ばれ、 "abc"がs1, s2両方で同じオブジェクトを指す様な形になるので s1 == s2でもtrueになります。

ですが、普通に文字列の比較をしたい場合には 必ずequalsで比較するべきです。

これと同じように、数字でもInteger型を使う時には ==で比較するとおかしくなることがあります。

1
2
3
4
5
6
7
8
Integer i1 = new Integer(1);
Integer i2 = new Integer(1);
if(i1 == i2){
  System.out.plingln("i1 == i2");
}
if(i1.equals(i2)){
  System.out.plingln("i1.equals(i2)");
}

とすると

i1.equals(i2)

なのでIntegerを比較する際にもequalsを使います。

Integerに直接数字を入れて

1
2
3
4
5
6
7
8
Integer i1 = 1;
Integer i2 = 1;
if(i1 == i2){
  System.out.plingln("i1 == i2");
}
if(i1.equals(i2)){
  System.out.plingln("i1.equals(i2)");
}

比較すると

i1 == i2
i1.equals(i2)

となります。 ただ、これは数値が-128から127までの間の場合だけで、 この間ではこれらの数字がおあんじオブジェクトとして扱われますが、 それ以上になるとIntegerに入れる時はインスタンス化されるので

1
2
3
4
5
6
7
8
Integer i1 = 200;
Integer i2 = 200;
if(i1 == i2){
  System.out.plingln("i1 == i2");
}
if(i1.equals(i2)){
  System.out.plingln("i1.equals(i2)");
}

比較すると

i1.equals(i2)

の様にequalsだけがtrueを返します。

まとめ

Pythonの場合もJavaの場合も最初の頃良くわからないまま 適当にやってしまうところですが、 両方見てみると==の意味合いが 逆な感じになってるのでちょっと混乱の元です。

というかちょっと混乱したのでまとめておきました。

  • Pythonで値を比較する時はisではなく==
  • JavaのStringやInteger等で値を比較する時は==ではなくequals
Sponsored Links
Sponsored Links

« Pythonでの引数の取り扱いの罠等 ブログとか文章で例として使えるドメインとかIPアドレス »

}