【问题标题】:Python classes: how to handle "future" instancesPython 类:如何处理“未来”实例
【发布时间】:2018-04-29 14:48:49
【问题描述】:

我正在自学 Python(2.7,之前没有编码经验),而且我刚刚开始处理类和 OOP 概念。作为练习,我正在尝试编写一个非常简单的地址簿。我想我设法理解了类和实例的基础知识,但我发现目前难以掌握的是如何进一步发展抽象级别。

试图更好地解释,比如说我有这个,这通常是许多教程用来介绍类的基本示例:

class Contact(object):    

    def __init__(self, name, surname, phone):

        self.name = name
        self.surname = surname
        self.phone = phone

contact1 = Contact('Mark', 'Doe', '123456789')
contact2 = Contact('Sally', 'Preston', '456789123')

到目前为止一切顺利,我可以使用contact1.attribute 或其他方法做很多其他有趣的事情。这里没问题。

我无法理解的内容如下:

问题 1:

我不知道我会有多少联系人。如果我不知道我将拥有多少个联系人,我该如何创建一个方法,比如 create_contact(),让我创建一个新联系人并将其存储在列表/字典中?我怎么称呼它? 我不明白如何制作它,这样我就可以创建一个新实例而无需硬编码其名称,如“contact1”等。我如何使“contact1”和“contact2”一行动态的东西?

我尝试使用列表作为类变量来解决问题。类似的东西(假设“contact_list”已经作为类变量存在):

Contact.contact_list.append(Contact('Mark', 'Doe','123456789')) # obviously I'd use raw_input instead of 'Mark' etc, but I avoided it here for readability

但我最终得到了一个无名对象列表,我的大脑很难处理它。我可以使用列表索引访问它们,但我不确定我是否在正确的轨道上......任何帮助将不胜感激。

问题 2:(有点相关,以便更好地理解问题)

如果在 python CLI 中我放了类似的东西(假设前面定义类的块已经运行):

>>> Contact('Bob', 'Stevens', '32165497')

我的理解是确实创建了一个具有这些属性的 Contact() 实例......但它没有名称。我如何访问它? (我怎么知道它存在?有没有办法列出与某个类相关的所有现有实例?)

我希望我说得有道理。提前感谢您的任何帮助。

【问题讨论】:

  • 在 SO 上,最好每个问题坚持一个问题。但至于您的第二个问题,当您这样做 Contact('Bob', 'Stevens', '32165497') 时,会创建一个实例,但由于您没有分配它或将其保存在列表等中,它会被丢弃,因此您无法访问它。
  • 顺便说一句,您应该认真考虑学习 Python 3,Python 2 将在 2020 年正式结束生命周期。Python 3 有许多改进,尤其是在您使用类。
  • 我开始使用 Python 2 只是因为我尝试的第一本书是旧版本的“Learn Python the Hard Way”。在他开始谈论 OOP 之后,我立即放弃了它。他假设太多,或者我对那本书不够聪明……不管怎样,现在我有点靠自己了,我已经在考虑切换到 Python 3,越早越好……对现在我知道的太少了,唯一的区别似乎是 print() 函数:D(当然不是,但我现在不知道更好)
  • FWIW,SO Python 聊天室常客do not recommend LPTHW;这本书有几个问题。 FWIW,您可以在任何其他导入之前将from __future__ import print_function, division 放在脚本顶部,从而获得 Python 3 print 和 Python 2.6+ 中的除法行为。但是使用实际的 Python 3 解释器要好得多。而且越早切换越好。这样,您就不必忘记 Python 3 已纠正的 Python 2 的各种“不幸”特性。
  • 这里是 Python 3 学习资源的简短列表:sopython.com/wiki/What_tutorial_should_I_read%3F

标签: python class oop instance


【解决方案1】:

将“无名”实例存储在集合中并没有错,但我同意一开始可能很难理解。 ;) 您不需要知道要创建多少联系人,因为 Python 集合类型都是动态的,所以您不需要提前指定大小,它们会增长以适应您提供的数据他们。

这是一个演示,它使用您的 Contact 类在列表字典中创建一个简单的电话簿。我们将每个联系人都保存在名字和姓氏下,因此我们可以按任一名称查找联系人。字典的值是列表,因此我们可以处理多个同名的人。

我在Contact 中添加了一个__repr__ 方法,以便于显示Contact 实例的内容。

from collections import defaultdict

class Contact(object):
    def __init__(self, name, surname, phone):
        self.name = name
        self.surname = surname
        self.phone = phone

    def __repr__(self):
        return '{name} {surname}: {phone}'.format(**self.__dict__)

phonebook = defaultdict(list)

data = [
    ('Mark', 'Doe', '123456789'),
    ('Sally', 'Preston', '456789123'),
    ('John', 'Doe', '789123456'),
]

for name, surname, phone in data:
    contact = Contact(name, surname, phone)
    phonebook[name].append(contact)
    phonebook[surname].append(contact)

for key, val in phonebook.items():
    print(key, val)

输出

Mark [Mark Doe: 123456789]
Doe [Mark Doe: 123456789, John Doe: 789123456]
Sally [Sally Preston: 456789123]
Preston [Sally Preston: 456789123]
John [John Doe: 789123456]

另一种选择是使phonebook 成为Contact 的类属性。


当然,要使这个程序真正有用,我们需要能够将电话簿保存到磁盘,并能够重新加载它。有多种方法可以做到这一点,例如,将数据保存到 CSV 或 JSON 文件,或 pickle 文件。但这些是另一个问题的主题。 ;)

【讨论】:

  • 开始将文件作为数据库处理正是我想到这个练习的原因,我会到达那里;) 我还没有看到 defaultdict(list) 是什么,但其余的似乎很清楚它有很大帮助,谢谢!为什么“Doe”作为键不会被覆盖?是因为defaultdict吗? (无论如何我都会自己检查文档,不需要大量回复,别担心 :))
【解决方案2】:

第一季度: 您可以创建另一个用作数据库的类

class Contact(object):    
    def __init__(self, name, surname, phone):
        self.name = name
        self.surname = surname
        self.phone = phone

class ContactDatabase:
    def __init__(self, *args):
        self.inner_list = list(args)

    def add_contact(self, new_contact):
        self.inner_list.append(new_contact)


# Initial contacts
contact1 = Contact('Mark', 'Doe', '123456789')
contact2 = Contact('Sally', 'Preston', '456789123')

# Creating a database
my_database = ContactDatabase(contact1, contact2)

# Adding new contacts later
my_database.add_contact(Contact('Jim', 'Miller', '111223123'))

【讨论】:

  • 所以,用惯用语言,我最终得到“my_database”,这是一个具有属性“inner_list”的实例,它是一个存储其他实例的列表。我对吗?但是这些实例都没有名称。我仍然不明白如何完全摆脱“contact1”等。有没有办法让用户选择将要创建的实例的名称?我也不能像你那样做吗,只向联系人类添加一个列表和一个向该列表添加实例的方法,而不添加类 ContactDatabase?
  • @Rahjael 说真的,您希望用户开始为您的程序中的变量命名,那样是疯狂的。见stackoverflow.com/questions/1373164/…stupidpythonideas.blogspot.com.au/2013/05/…
  • @pm2ring 感谢您的参考,我会检查这些。但让我澄清一下:我并不是真的让最终的“用户”选择变量名......我只是在为无名对象列表的概念而苦苦挣扎。在你上面的例子之后,我想我开始明白了。基本上你完全放弃了变量名,并开始引用无名对象来调用 dict 键或实例的属性。这样对吗?我想我错过了范式的这种概念跳跃。
  • 嗯,这个例子展示了一种方法,如何避免将类实例分配给变量,并简单地将其存储在一种可能对您的应用程序有用的好方法中。变量名本身是无关紧要的和任意的——实际的名字contact1和contact2永远不会存储在任何地方。存储的是实例化的类。
猜你喜欢
  • 1970-01-01
  • 2021-06-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多