追加要列出的类的实例?

时间:2019-06-28 15:57:00

标签: python

我正在尝试创建一个命令行工具,以使用Pickle和Argparse与Python保存联系。当添加联系人时,解析器将查找三个参数,第一个,最后一个和数字。

我已经看过尽可能多的论坛和堆栈溢出问题,但没有一个真正适合我的情况。 该程序具有-a(--add),-rm(--remove)和-l(--list)三个选项。三个函数处理参数,add_contact,remove_contact,list_contacts。

我的课看起来像这样:

class Contact:
    def __init__(self, first, last, number):
        self.first = first
        self.last = last
        self.number = number

    def __len__(self):
        global contacts
        return len(contacts)

    def __iter__(self):
        return self

单个联系人应具有“第一”,“最后”和“号码”属性。 此功能列出了联系人:

def list_contacts:
    try:
        print("Contacts:")
        f = open('c.data', 'rb')
        contacts = pickle.load(f)
        f.close()
        for contact in contacts:
            print(first+" "+last+": " + number)
        print(str(len(contacts)) + " contacts total.")
        if len(contacts) == 0:
            print("No contacts, why don't you add some first?")
     except FileNotFoundError:
         print("No contacts, why don't you add some first?")

现在,我认为问题出在我的Main()函数中,其中的Contact实例称为:

def Main():
    first = args.first
    last = args.last
    number = args.number
    # The issue:
    contact = Contact(first, last, number)
    if args.add and first and last and number:
        add_contact(contact)
    elif args.remove and first and last and number:
        delete_contact(contact)
    elif args.list:
        list_contacts()

我希望我的程序列出这样的联系人:

First Last: Number
First Last: Number
2 contact total.

相反,如果我要使其以某种方式工作,它将像这样运行:

First 
Last
Number
3 contacts total

我想创建一个具有first,last和number属性作为一个对象的Contact类实例,并将其附加到联系人列表中。相反,当我列出它们时,我得到了:

Contacts:
Traceback (most recent call last):
  File "contacts.py", line 105, in <module>
    Main()
  File "contacts.py", line 102, in Main
    list_contacts()
  File "contacts.py", line 50, in list_contacts
    for contact in contacts:
TypeError: iter() returned non-iterator of type 'Contact'

如果这没有为您提供足够的上下文,则可以在这里找到整个程序:https://pastebin.com/CqJwPVL2 我被困住了, iter 功能无法解决此问题。请帮我! 预先谢谢你

1 个答案:

答案 0 :(得分:0)

问题是您使用pickle.load(f)好像可以自动将所有腌制对象作为列表加载一样,但是由于您将每个新联系人都添加为单个转储添加到文件中,因此实际上没有有一个列表。

您有两种可能性:

  1. 将联系人转储为列表。这样,当您使用pickle.load时,您将立即在列表中获得所有联系人,然后然后可以对其进行迭代。

  2. 保持转储联系人一对一,但在加载联系人时会建立一个列表。 pickle.load将返回文件中的下一个腌制对象,因此,如果其中有多个联系人,则必须对其进行迭代并构建列表,或者仅在打印功能中使用它。

例如:

tot = 0
while 1:
    try:
        contact = pickle.load(f)
        print(contact)
        tot += 1
    except:
        print("Total contacts: {}".format(tot))
        break

有关使用此列表的更多详细信息,请参见this answer


编辑

鉴于评论中的更新,这里有一些代码修补程序。

class Contact:

def __init__(self, first, last, number):
    self.first = first
    self.last = last
    self.number = number

def __len__(self):
    global contacts
    return len(contacts)

def __str__(self):
    return self.first + " "+ self.last + ": " + self.number

def __eq__(self, other):
    if self.name == other.name and self.surname == other.surname:
        return True
    return False

__str__(self)方法应返回有关对象本身的信息(字符串),您正在做的工作是返回一个超出其范围的列表。 我还要补充一点,仅从一个Contact中返回整个联系人列表长度在语义上是错误的。相反,我会在len(contact)内的不是的其他地方使用一个简单的Contact

__eq__方法已添加,供以后在delete_contact方法中使用。

def load_contacts(filename="c.data"):
    try:
        f = open("c.data", "rb")
        contact_list = pickle.load(f)
        f.close()
        return contact_list
    except FileNotFoundError:
        return []


def list_contacts(filename):
    contacts = load_contacts(filename)
    for contact in contacts:
        print(contact)
    print("Total contacts: {}".format(len(contacts))) 
    if len(contacts) == 0:
        print("No contacts, why don't you add some first?")


def add_contact(contact):
    contacts = load_contacts()
    contacts.append(contact)
    f = open('c.data', 'wb')
    pickle.dump(contacts, f)
    f.close()
    print("Contact added")

def delete_contact(contact):
    contact_list = load_contacts()
    if len(contact_list) == 0:
        print("No contacts, why don't you add some first?")
        return           
    try:
        contact_list.remove(contact)
        f = open("c.data", "wb")
        pickle.dump(contact_list, f)
        f.close()
    except ValueError:
        print("No such a contact to remove")

def Main():
    first = args.first
    last = args.last
    number = args.number

    if args.list:
        list_contacts('c.data')
    else:
        if not args.first or not args.last or not args.number:
            print("Contact info missing")
            return

        contact = Contact(first, last, number)
        if args.add:
            add_contact(contact)
        elif args.remove:
            delete_contact(contact)

好的,您的代码中有些混乱,因此我进行了一些更改并重新组织了它。我将尝试解释我的更改:

  1. 主要:我通过将联系信息检查移到此处而不是在add_contact内来重新组织了逻辑,同样仅 创建了联系人如果此类信息不是None。这是因为从语法上来说,执行这种检查更为正确,因为它不在add_contact方法的范围内。

  2. load_contacts :由于始终需要首先加载联系人数据,因此最好将逻辑打包为一个方法。如果没有数据,此方法将返回一个空列表。

  3. list_contacts :现在,它只需遍历已加载的联系人

  4. add_contact :加载联系人列表后,只需将新联系人添加到该列表中,然后将整个列表转储到文件中。请注意,该文件以 wb 模式打开,不是 ab 模式打开,因为您每次都转储整个列表。

  5. delete_contact :应在开始时检查联系人列表的长度。对于其余部分,它非常简单:如果列表不为空,它将尝试从其中删除一个项目,否则不做任何事情。请注意,可以从列表中删除,因为我们之前已经在Contact类中定义了 eq 方法。

希望一切都清楚。