Python:在创建新对象前检查对象是否已存在
请帮我看看我下面的代码有什么问题。我首先创建了三个我的类的对象,并把它们放进一个集合列表里。在创建任何新的对象之前,我想先检查一下,确保这个人还不在列表里。如果这个人已经存在,就不应该再创建一次。我原本想通过这个条件来实现这个检查:if prompt_fname == person.fname and prompt_lname == person.lname:
。显然,我的做法不对,因为程序还是继续运行,创建了已经在列表里的同一个人,结果创建了两次。请问我该如何修改代码,以确保列表中已经存在的人不会被再次创建。同时,任何新的人也不应该在循环的每次迭代中被重复创建。我刚开始学习编程,所以请在回答中不要省略太多细节。非常感谢。
class Person(object):
personslist = []
'''Creates a person object'''
def __init__(self, firstname, lastname):
self.lname = lastname.title()
self.fname = firstname.title()
Person.personslist.append(self)
def __str__(self):
return "{0} {1}".format(self.fname, self.lname)
def __repr__(self):
return "{0} {1}".format(self.fname, self.lname)
Person("Adamu", "Emeka")
Person("Femi", "Ojukwu")
Person("Wole", "Jonathan")
prompt_fname = "Adamu"
prompt_lname = "Emeka"
print(Person.personslist)
for person in Person.personslist:
if prompt_fname == person.fname and prompt_lname == person.lname:
pass
else:
Person(prompt_fname, prompt_lname)
print(Person.personslist)
输出结果
[Adamu Emeka, Femi Ojukwu, Wole Jonathan]
[Adamu Emeka, Femi Ojukwu, Wole Jonathan, Adamu Emeka, Adamu Emeka]
使用 Python 3.4.1
5 个回答
在你的代码中,一旦找到一个不是 Adamu Emeka 的人,你就会再往列表里加一个 Adamu Emeka。这就是为什么会出现两个 Adamu Emeka 的原因。你可以试试下面的方法:
alreadyExists = False;
for person in Person.personslist:
if prompt_fname == person.fname and prompt_lname == person.lname:
alreadyExists = True;
break;
if not alreadyExists:
Person(prompt_fname, prompt_lname)
一个更好的方法是使用 set
,这样你就不需要进行线性搜索了。为了让 set
正常工作,你需要 实现 __hash__
和 __eq__
方法。
试试这个:
if prompt_fname.title() == person.fname and prompt_lname.title() == person.lname:
因为你在Person的初始化方法init里用了title()这个方法。
在添加名字之前,每次都要检查完整的列表:
name = prompt_fname + prompt_lname
if not any(person.fname + person.lname == name for person in Person.personslist):
Person(prompt_fname, prompt_lname)
这段代码没有按预期工作:
for person in Person.personslist:
if prompt_fname == person.fname and prompt_lname == person.lname:
pass
else:
Person(prompt_fname, prompt_lname)
在这行代码 for person in Person.personslist:
中,它会遍历你已经创建的三个 Person() 对象。第一个对象是 'Adamu Emeka',所以名字是相等的,这时 'if' 语句就会执行到 'pass',也就是跳过不做任何事情。不过,接下来在 personslist 中的下一个对象名字是 'Femi Ojukwu',这时 'if' 里的条件不成立,就会进入 else
部分,创建一个新的对象。第三个名字也是这样。这就是为什么你会多出两个 'Adamu Emeka' 的原因。
想了解其他解决方案,可以看看 Daniel Roseman 的回答。
你的循环在检查每一项,如果这一项不相等,就会创建一个新的实例。但是如果这一项是相等的,它不会停止,而是继续检查下一个,这个下一个肯定也不会相等。所以这就是为什么你最后会多出两个条目的原因。
你可以通过设置一个标志来解决这个问题:
found = False
for person in Person.personslist:
if prompt_fname == person.fname and prompt_lname == person.lname:
found = True
break
if not found:
Person(prompt_fname, prompt_lname)
不过,还有一种更好的方法:你现在的方法效率很低,因为每次都需要线性扫描。相反,你可以保持一个以完整名称为键的对象字典:
class Person(object):
persons_dict = {}
'''Creates a person object'''
def __init__(self, firstname, lastname):
self.lname = lastname.title()
self.fname = firstname.title()
fullname = "%s %s" % (self.fname, self.lname)
Person.persons_dict[fullname] = self
这样你就可以一次性简单地检查:
if "%s %s" % (prompt_fname, prompt_lname) not in Person.persons_dict: