重载身份运算符的目的

时间:2014-01-18 03:54:36

标签: python oop comparison-operators object-identity

为什么在overload the identity comparison运算符的Python中无法实现?每个其他比较运算符都可以自定义,为什么不进行身份比较?

3 个答案:

答案 0 :(得分:2)

你不能覆盖'is',因为它通过比较它们的内存地址(即指针比较)来测试两个对象是否是同一个对象。

答案 1 :(得分:1)

简单地说,因为身份运算符的目的是测试身份。身份意味着“对象真正是什么”。操作员的整个要点是能够测试两个对象是否“真的”是同一个对象,而不是根据他们自己的规则“是否”被认为是相同的。

答案 2 :(得分:1)

支持具有可变状态的对象的编程语言通常提供一个操作符,该操作符可以测试两个对象实际上是否是相同的对象。在这种情况下,“相同”意味着对象实际上是同一个对象(例如,内存中的相同字节块(或者编译器设计者选择表示对象)。但是,对于许多类型的数据结构,程序员可能更为突出的其他类型的等价关系。例如,给定一个List接口,程序员可能只关心两个列表是否包含相同顺序的等效元素。这只在有一些情况下才有意义。可以区分具有等效元素的两个列表的方式。因为许多编程语言支持可变状态,所以改变对象状态的操作就是这种对象可以被区分的方式。

例如,给定一个可变的列表实现,我们可能会:

x = make a list of 1 2 3
y = x
z = make a list of 1 2 3 4

x same as y?  yes.
x equal to y? yes.
x same as z?   no.
x equal to z?  no.

add 4 to end of x

x same as y?  yes.
x equal to y? yes.
x same as z?   no.
x equal to z? yes. ##

在一个没有可变状态的函数式编程语言中,或者甚至在一个具有可变状态的语言中,但我们使用函数式的函数,我们不会破坏性地修改这样的列表,而是< strong> add 操作会返回一个新列表(可能与其他人共享结构)。在这种情况下,任何元素序列都只能有一个列表,所以我们可以:

x = make a list of 1 2 3
y = x
z = make a list of 1 2 3 4

x same as y?  yes.
x equal to y? yes.
x same as z?   no.
x equal to z?  no.

x' = add 4 to end of x

x same as y?  yes.
x equal to y? yes.
x same as z?   no.
x equal to z?  no.
x same as x'?  no.
x equal to x'? no.

x' same as x?    no.
x' equal to x?   no.
x' same as z?   yes. ## or no, depending on implementation
x' equal to z?  yes.
x' same as x'?  yes.
x' equal to x'? yes.

事实

x same as y?  yes.
x equal to y? yes.
x same as z?   no.
x equal to z?  no.

始终保持不变可以有助于推断程序的行为。

当我们以面向对象的方式进行编程时,对象标识是一个重要的概念,并且实际上是该语言的基元之一,就像布尔运算符或数值比较一样。如果它可以被覆盖,则无法执行整类优化,并且您可以引入一些非常难以追踪的错误。例如,考虑(可能是人为的例子):

# frob x and y, but never frob an object twice
frobBoth x y
  if x same as y         # **
    frob x
  else
    frob x
    frob y
  end if

如果您可以覆盖same as,那么frobx可能不会y,因为same as即使x也可以返回true }和y不是同一个对象。

在对象标识可能很重要的语言中,需要有一个无法覆盖的对象标识运算符。引入一个可以某种方式重写的相等运算符通常也很有用,这样就可以很容易地检查两个对象是否以某种有用的方式是等价的(这将特定于对象的类型)。

  • 在Python中,身份运算符为is,等于运算符为==,可以通过__eq__方法进行自定义。
  • 另一个例子,在Java中,身份运算符是==,等于运算符是Object.equals(Object)

值得注意的是,在许多语言中,相等运算符的默认实现对象标识。这可能很好,因为对象身份通常比其他更复杂的平等关系更快地进行测试。