Python:在创建新对象前检查对象是否已存在

2 投票
5 回答
9495 浏览
提问于 2025-04-18 18:04

请帮我看看我下面的代码有什么问题。我首先创建了三个我的类的对象,并把它们放进一个集合列表里。在创建任何新的对象之前,我想先检查一下,确保这个人还不在列表里。如果这个人已经存在,就不应该再创建一次。我原本想通过这个条件来实现这个检查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 个回答

-1

在你的代码中,一旦找到一个不是 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__ 方法

0

试试这个:

if prompt_fname.title() == person.fname and prompt_lname.title() == person.lname:

因为你在Person的初始化方法init里用了title()这个方法。

1

在添加名字之前,每次都要检查完整的列表:

name = prompt_fname + prompt_lname

if not any(person.fname + person.lname == name for person in Person.personslist):
    Person(prompt_fname, prompt_lname)
1

这段代码没有按预期工作:

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 的回答。

7

你的循环在检查每一项,如果这一项不相等,就会创建一个新的实例。但是如果这一项是相等的,它不会停止,而是继续检查下一个,这个下一个肯定也不会相等。所以这就是为什么你最后会多出两个条目的原因。

你可以通过设置一个标志来解决这个问题:

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:

撰写回答