检查对象是否在列表中(不是 "by value",而是通过 id)
Check if object is in list (not "by value", but by id)
考虑以下代码:
>>> class A(object):
... def __init__(self, a):
... self.a = a
... def __eq__(self, other):
... return self.a==other.a
...
>>> a=A(1)
>>> b=A(1)
>>> c=A(2)
>>> a==b
True # because __eq__ says so
>>> a==c
False # because __eq__ says so
>>> a is b
False # because they're different objects
>>> l = [b,c]
>>> a in l
True # seems to use __eq__ under the hood
因此,in
似乎使用 __eq__
来确定某物是否在容器中。
- 在哪里可以找到有关此行为的文档?
- 是否可以让
in
使用对象标识,a.k.a。 a in somelist
如果对象 a
在 somelist
中,而不是其他比较等于 a
的对象?
使用 any()
function 和生成器表达式:
any(o is a for o in l)
in
的行为记录在 Common Sequence Operators section:
x in s
True
if an item of s is equal to x, else False
大胆强调我的。
如果您必须使用 in
,请使用带有使用 is
的自定义 __eq__
方法的包装器对象,或者在自定义 __contains__
method 使用的地方构建您自己的容器is
针对每个包含的元素进行测试。
包装器可能如下所示:
class IdentityWrapper(object):
def __init__(self, ob):
self.ob = ob
def __eq__(self, other):
return other is self.ob
演示:
>>> IdentityWrapper(a) in l
False
>>> IdentityWrapper(a) in (l + [a])
True
容器可以只使用上面概述的相同 any()
函数:
class IdentityList(list):
def __contains__(self, other):
return any(o is other for o in self)
演示:
>>> il = IdentityList(l)
>>> a in il
False
>>> a in IdentityList(l + [a])
True
如果您不想改变A
行为,您可以为用过的容器准备薄包装纸。要改变 in
运算符的行为方式,魔术方法 __contains__
需要被覆盖。引用文档:
Called to implement membership test operators. Should return true if
item is in self, false otherwise. For mapping objects, this should
consider the keys of the mapping rather than the values or the
key-item pairs.
示例代码:
class A(object):
def __init__(self, a):
self.a = a
def __eq__(self, other):
return self.a == other.a
class IdentityList(list):
def __contains__(self, obj):
return any(o is obj for o in self)
a = A(1)
b = A(1)
c = A(2)
container = [b, c]
identity_container = IdentityList(container)
assert a in container # not desired output (described in question)
assert a not in identity_container # desired output
考虑以下代码:
>>> class A(object):
... def __init__(self, a):
... self.a = a
... def __eq__(self, other):
... return self.a==other.a
...
>>> a=A(1)
>>> b=A(1)
>>> c=A(2)
>>> a==b
True # because __eq__ says so
>>> a==c
False # because __eq__ says so
>>> a is b
False # because they're different objects
>>> l = [b,c]
>>> a in l
True # seems to use __eq__ under the hood
因此,in
似乎使用 __eq__
来确定某物是否在容器中。
- 在哪里可以找到有关此行为的文档?
- 是否可以让
in
使用对象标识,a.k.a。a in somelist
如果对象a
在somelist
中,而不是其他比较等于a
的对象?
使用 any()
function 和生成器表达式:
any(o is a for o in l)
in
的行为记录在 Common Sequence Operators section:
x in s
True
if an item of s is equal to x, elseFalse
大胆强调我的。
如果您必须使用 in
,请使用带有使用 is
的自定义 __eq__
方法的包装器对象,或者在自定义 __contains__
method 使用的地方构建您自己的容器is
针对每个包含的元素进行测试。
包装器可能如下所示:
class IdentityWrapper(object):
def __init__(self, ob):
self.ob = ob
def __eq__(self, other):
return other is self.ob
演示:
>>> IdentityWrapper(a) in l
False
>>> IdentityWrapper(a) in (l + [a])
True
容器可以只使用上面概述的相同 any()
函数:
class IdentityList(list):
def __contains__(self, other):
return any(o is other for o in self)
演示:
>>> il = IdentityList(l)
>>> a in il
False
>>> a in IdentityList(l + [a])
True
如果您不想改变A
行为,您可以为用过的容器准备薄包装纸。要改变 in
运算符的行为方式,魔术方法 __contains__
需要被覆盖。引用文档:
Called to implement membership test operators. Should return true if item is in self, false otherwise. For mapping objects, this should consider the keys of the mapping rather than the values or the key-item pairs.
示例代码:
class A(object):
def __init__(self, a):
self.a = a
def __eq__(self, other):
return self.a == other.a
class IdentityList(list):
def __contains__(self, obj):
return any(o is obj for o in self)
a = A(1)
b = A(1)
c = A(2)
container = [b, c]
identity_container = IdentityList(container)
assert a in container # not desired output (described in question)
assert a not in identity_container # desired output