我正在尝试创建一个命令行工具,以使用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 功能无法解决此问题。请帮我! 预先谢谢你
答案 0 :(得分:0)
问题是您使用pickle.load(f)
好像可以自动将所有腌制对象作为列表加载一样,但是由于您将每个新联系人都添加为单个转储添加到文件中,因此实际上没有有一个列表。
您有两种可能性:
将联系人转储为列表。这样,当您使用pickle.load
时,您将立即在列表中获得所有联系人,然后然后可以对其进行迭代。
保持转储联系人一对一,但在加载联系人时会建立一个列表。 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)
好的,您的代码中有些混乱,因此我进行了一些更改并重新组织了它。我将尝试解释我的更改:
主要:我通过将联系信息检查移到此处而不是在add_contact
内来重新组织了逻辑,同样仅 创建了联系人如果此类信息不是None
。这是因为从语法上来说,执行这种检查更为正确,因为它不在add_contact方法的范围内。
load_contacts :由于始终需要首先加载联系人数据,因此最好将逻辑打包为一个方法。如果没有数据,此方法将返回一个空列表。
list_contacts :现在,它只需遍历已加载的联系人
add_contact :加载联系人列表后,只需将新联系人添加到该列表中,然后将整个列表转储到文件中。请注意,该文件以 wb 模式打开,不是 ab 模式打开,因为您每次都转储整个列表。
delete_contact :应在开始时检查联系人列表的长度。对于其余部分,它非常简单:如果列表不为空,它将尝试从其中删除一个项目,否则不做任何事情。请注意,可以从列表中删除,因为我们之前已经在Contact类中定义了 eq 方法。
希望一切都清楚。