我有一个简单的类定义如下:
class User(object):
def __init__(self, id=None, name=None):
self.id = id
self.name = name
def __contains__(self, item):
return item == self.id
Run Code Online (Sandbox Code Playgroud)
使用此类,我可以对该类的单个实例进行简单检查,如下所示:
>>> user1 = User(1, 'name_1')
>>> 1 in user1
True
>>> 2 in user1
False
Run Code Online (Sandbox Code Playgroud)
这按预期工作。
我如何检查一个值是否在对象列表中User?它似乎总是返回 False。
例子:
from random import randint
from pprint import pprint
users = [User(x, 'name_{}'.format(x)) for x in xrange(5)]
pprint(users, indent=4)
for x in xrange(5):
i = randint(2,6)
if i in users:
print("User already exists: {}".format(i))
else:
print("{} is not in users list. Creating new user with id: {}".format(i, i))
users.append(User(i, 'new_user{}'.format(i)))
pprint(users, indent=4)
Run Code Online (Sandbox Code Playgroud)
这将创建与此类似的输出:
[ 0 => name_0,
1 => name_1,
2 => name_2,
3 => name_3,
4 => name_4]
6 is not in users list. Creating new user with id: 6
6 is not in users list. Creating new user with id: 6
6 is not in users list. Creating new user with id: 6
3 is not in users list. Creating new user with id: 3
3 is not in users list. Creating new user with id: 3
[ 0 => name_0,
1 => name_1,
2 => name_2,
3 => name_3,
4 => name_4,
6 => new_user6,
6 => new_user6,
6 => new_user6,
3 => new_user3,
3 => new_user3]
Run Code Online (Sandbox Code Playgroud)
问题是具有 id 的用户6应该只被创建 1 次,因为它还没有被创建。第二次、第三次6,应该都失败了。用户 id3根本不应该被重新创建,因为它是变量初始化的一部分users。
在与我的类的多个实例进行比较时,如何修改__contains__方法才能正确利用?in
如果users是用户列表并且您进行了检查if i in users,那么您就没有进行检查User.__contains__。你正在检查list.__contains__。无论你做什么都User.__contains__不会影响检查是否i在列表中的结果。
如果你想检查是否i匹配任何Userin users,你可以这样做:
if any(i in u for u in users)
Run Code Online (Sandbox Code Playgroud)
或者更清楚一点:
if any(u.id==i for u in users)
Run Code Online (Sandbox Code Playgroud)
User.__contains__并完全避免使用。
__eq__这似乎是您确实想要定义接受与其他User对象 和的比较的情况int。这将使 contains 检查自动工作,并且在一般用法中比在非容器类型上User实现更有意义。__contains__
import sys
from operator import index
class User(object): # Explicit inheritance from object can be removed for Py3-only code
def __init__(self, id=None, name=None):
self.id = id
self.name = name
def __eq__(self, item):
if isinstance(item, User):
return self.id == item.id and self.name == item.name
try:
# Accept any int-like thing
return self.id == index(item)
except TypeError:
return NotImplemented
# Canonical mirror of __eq__ only needed on Py2; Py3 defines it implicitly
if sys.version_info < (3,):
def __ne__(self, other):
equal = self.__eq__(other)
return equal if equal is NotImplemented else not equal
def __hash__(self):
return self.id
Run Code Online (Sandbox Code Playgroud)
现在您可以将您的类型与普通集合(包括set和dict键)一起使用,并且可以轻松查找它。
from operator import attrgetter
# Use set for faster lookup; can sort for display when needed
users = {User(x, 'name_{}'.format(x)) for x in xrange(5)}
pprint(sorted(users, key=attrgetter('id')), indent=4)
for x in xrange(5):
i = randint(2,6)
if i in users:
print("User already exists: {}".format(i))
else:
print("{} is not in users list. Creating new user with id: {}".format(i, i))
users.add(User(i, 'new_user{}'.format(i)))
pprint(sorted(users, key=attrgetter('id')), indent=4)
Run Code Online (Sandbox Code Playgroud)
这是对 的滥用__contains__。您可能希望__contains__在像UserList.
更好的方法是id直接在生成器表达式或列表理解中访问属性(而不是使用 in 运算符)。例如。
class User(object):
def __init__(self, id=None, name=None):
self.id = id
self.name = name
user = User(1, 'name_1')
assert 1 == user.id
user_list = [user, User(2, 'name_2')]
assert any(2 == u.id for u in user_list)
Run Code Online (Sandbox Code Playgroud)
然后,对于随机示例,您将使用集合或字典来存储已存在的用户的 ID。
users = [User(x, 'name_{}'.format(x)) for x in xrange(5)]
ids = set(u.id for u in users)
for x in xrange(5):
i = randint(2,6)
if i in ids:
print("User id already exists: {}".format(i))
else:
print("{} is not in users list. Creating new user with id: {}".format(i, i))
ids.add(i)
users.append(User(i, 'new_user{}'.format(i)))
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
7033 次 |
| 最近记录: |