【问题标题】:How do I create a list or set object in a class in Python?如何在 Python 的类中创建列表或设置对象?
【发布时间】:2011-01-18 15:14:05
【问题描述】:

对于我的项目,讲师(定义为一个班级)的角色是为学生提供项目。项目本身也是一个类。我有一些全局字典,由唯一的数字 id 键入,用于映射到对象的讲师和项目。

因此对于“讲师”字典(当前):

lecturer[id] = Lecturer(lec_name, lec_id, max_students)

我目前正在读取从数据库生成的以空格分隔的文本文件。我没有直接访问数据库的权限,所以我对文件的格式没有太多发言权。这是一个虚构的 sn-p,它显示了文本文件的结构。请见谅。

0001 001 "Miyamoto, S." "Even Newer Super Mario Bros"
0002 001 "Miyamoto, S." "Legend of Zelda: Skies of Hyrule"
0003 002 "Molyneux, P." "Project Milo"
0004 002 "Molyneux, P." "Fable III"
0005 003 "Blow, J." "Ponytail"

每一行的结构基本都是proj_id, lec_id, lec_name, proj_name

现在,我正在将相关数据读入相关对象。因此,proj_id 存储在class Project 中,而lec_nameclass Lecturer 对象等。 LecturerProject 类目前不相关。

但是,当我从文本文件中读取每一行时,对于该行,我希望将讲师提供的项目读入Lecturer 类;我已经将proj_id 读入Project 类。我想在Lecturer 中创建一个名为offered_proj 的对象,它应该是该讲师提供的项目的集合或列表。因此,每当我在同一lec_id 下的新项目中读取一行时,offered_proj 将使用该项目进行更新。如果我想显示讲师提供的项目列表,理想情况下我只想使用print lecturers[lec_id].offered_proj

我的 Python 不是很好,如果有人能告诉我一种方法,我将不胜感激。我不确定它作为一个集合还是一个列表更好。

Update

Alex MartelliOddthinking 的建议下,我回去做了一些更改并尝试打印结果。

这里是sn-p的代码:

for line in csv_file:
    proj_id = int(line[0])
    lec_id = int(line[1])
    lec_name = line[2]
    proj_name = line[3]
    projects[proj_id] = Project(proj_id, proj_name)
    lecturers[lec_id] = Lecturer(lec_id, lec_name)
    if lec_id in lecturers.keys():
        lecturers[lec_id].offered_proj.add(proj_id)
    print lec_id, lecturers[lec_id].offered_proj

print lecturers[lec_id].offered_proj 行打印以下输出:

001 set([0001])
001 set([0002])
002 set([0003])
002 set([0004])
003 set([0005])

基本上感觉这个系列被改写了或类似的。因此,如果我尝试为特定讲师打印print lec_id, lecturers[001].offered_proj,我得到的只是最后一个已读入的proj_id

【问题讨论】:

  • 提示:“我得到的只是最后一个被读入的 proj_id。” lecturers[lec_id].offered_proj 的代码实际上是做什么的?它一定是在创造一个新的、空的集合。也发布该代码。

标签: python class dictionary


【解决方案1】:

set 更好,因为您不关心订单并且没有重复。

您可以使用csv 模块轻松解析文件(使用delimiter' ')。

一旦您拥有lec_name,您必须检查该讲师是否已经知道;为此,保留从lec_name 到讲师对象的字典(这只是对同一讲师对象的另一个引用,您也可以从lecturer 字典中引用该对象)。在找到不在该词典中的lec_name 时,您知道它是以前未见过的讲师,因此仅在这种情况下创建一个新的讲师对象(并将其粘贴在两个字典中),并提供一组空的课程。最后,只需将课程.add 发送到当前讲师的offered_proj。这真的是一个非常流畅的流程。

您是否尝试过实施此流程?如果是这样,你有什么问题?你能告诉我们相关的代码吗?最多应该有十几行?

编辑:由于 OP 现在已经发布了代码,我可以发现错误——它就在这里:

lecturers[lec_id] = Lecturer(lec_id, lec_name)
if lec_id in lecturers.keys():
    lecturers[lec_id].offered_proj.add(proj_id)

这是无条件地创建一个新的讲师对象(践踏lecturers dict 中的旧对象,如果有的话),所以当然前一组会被丢弃。这是您需要的代码:首先检查,仅在需要时创建! (另外,小错误,不要检查in....keys(),这非常低效 - 只需检查字典中的存在)。如下:

if lec_id in lecturers:
    thelec = lecturers[lec_id]
else:
    thelec = lecturers[lec_id] = Lecturer(lec_id, lec_name)
thelec.offered_proj.add(proj_id)

你可以用几种不同的方式表达这一点,但我希望这已经足够清楚了。为了完整起见,我通常会用以下方式来表达它(以避免两次查找字典)如下:

thelec = lecturers.get(lec_id)
if thelec is None:
    thelec = lecturers[lec_id] = Lecturer(lec_id, lec_name)
thelec.offered_proj.add(proj_id)

【讨论】:

  • 啊,谢谢。我实际上正在使用csv.readerdelimiter = ' '。我不想补充,因为我认为这个问题有点过于冗长了。
  • 好的,所以你已经有了我在第一段中的建议;-)。第二段应该还是有用的。
  • 尝试在此处粘贴一些代码,但失败得很惨。我按照 Oddthinking 的建议做了:在 Lecturer 类中添加了集合创建。当我在解析的文件中阅读时,我正在设置:proj_id = int(line[0]) 我对其他元素执行类似的分配。然后将所有相关数据读入全局字典:projects[proj_id] = Project(proj_id, proj_name)lecturers[lec_id] = Lecturer(lec_id, lec_name) 之后我有一个if 语句来检查讲师是否真的在字典中,然后它会尝试添加项目。
  • 问题是当我打电话给lecturers[lec_id].offered_proj.add(proj_id) 时,我没有得到一组项目。我每次都得到一个新的集合,也就是说,它似乎没有添加到原始集合中。
  • 我弄清楚了我做错了什么并回答了自己,因为我无法弄清楚如何在 cmets 中发布代码。不过感谢您的帮助!
【解决方案2】:

当您想保证每个项目只有一个实例时,集合很有用。在计算集合中是否存在项目时,它们也比列表更快。

列表在添加项目时速度更快,并且还具有排序。

这听起来像你想要一套。你听起来已经很接近了。

在 Lecturer.init 中,添加一行:

self.offered_proj = set()

这将形成一个空集。

当您在项目中阅读时,您可以简单地添加到该集合中:

lecturer.offered_proj.add(project)

您可以按照您的建议进行打印(尽管您可能喜欢美化它。)

【讨论】:

  • 感谢您的提示。我目前正在尝试。
【解决方案3】:

感谢AlexOddthinking 的帮助!我想我已经弄清楚发生了什么:

我修改了添加到问题中的代码 sn-p。基本上,每次它阅读该行时,我认为它正在重新创建讲师对象。因此,我添加了另一个if 语句来检查字典中是否已经存在lec_id。如果是这样,那么它会跳过对象创建并简单地将项目添加到offered_proj 集。

我所做的更改是:

if not lec_id in lecturers.keys():
    projects[proj_id] = Project(proj_id, proj_name)
lecturers[lec_id] = Lecturer(lec_id, lec_name)
lecturers[lec_id].offered_proj.add(proj_id)

感谢我的朋友 Samir,我最近才发现 if not 背后的概念。

现在我得到以下输出:

001 set([0001])
001 set([0001, 0002])
002 set([0003])
002 set([0003, 0004])
003 set([0005])

如果我 print 选择了一个 lec_id,我会得到完全更新的集合。欢乐。

【讨论】:

  • 好消息。您可以将第一行缩写为“如果 lec_id 不在讲师中:”
  • 哦,等一下。如果讲师是新来的,您只会创建项目。第二行代码不应该在 if 语句中。它应该始终运行。
猜你喜欢
  • 2013-07-01
  • 1970-01-01
  • 2022-11-05
  • 2010-09-25
  • 1970-01-01
  • 1970-01-01
  • 2020-09-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多