我有两个不同的对象。其中一个在list或tuple属性中包含N个其他类型的对象。让我们说课堂上的学生:
class Student:
def __init__(self, name):
self.name = name
class ClassRoom:
def __init__(self, students):
self.students = students
当然,我们有大量的Student和ClassRoom实例:
john, sam = Student('John'), Student('Sam')
patrick, michael, bill = Student('Patrick'), Student('Michael'), Student('Bill')
klass1 = ClassRoom([john, sam])
klass2 = ClassRoom([patrick, michael, bill])
考虑到每个学生的名字都是独一无二的,你不能通过参考这样的方式进入学生的课堂:
sam.get_classroom() # Student class doesn't support this :(
我们有一个辅助功能来完成这项工作:
def get_classroom_by_student(klasses, student_name):
for klass in klasses:
for student in klass.students:
if student.name==student_name:
return klass
# Or yield if a student belongs to more than one class
sams_class = get_classroom_by_student([klass1, klass2], 'Sam')
bills_class = get_classroom_by_student([klass1, klass2], 'Bill')
由于“Flat优于嵌套”,我如何创建一个高效的生成器,或者是否有一些pythonic方法来实现这个辅助函数?
答案 0 :(得分:1)
假设您不想更改数据模型,可以像这样重写您的函数:
def get_classroom_by_student(klasses, student_name):
for klass in klasses:
for student in klass.students:
if student.name==student_name:
yield klass
这更不等于
def get_classroom_by_student(klasses, student_name):
combinations = []
for klass in klasses:
for student in klass.students:
if student.name==student_name:
combinations.append(klass)
return combinations
但是,清洁剂如下:
def get_classroom_by_student(klasses, student):
for klass in klasses:
for s in klass.students:
if s is student:
yield klass
这可以使用嵌套列表理解重写:
def get_classroom_by_student(klasses, student):
return [klass for klass in klasses for s in klass.students if s is student]
甚至更短
def get_classroom_by_student(klasses, student):
return [klass for klass in klasses if student in klass.students]
答案 1 :(得分:0)
这个怎么样:
class Student:
def __init__(self, name):
self.name = name
class ClassRoom:
def __init__(self, students):
self.students = students
john, sam = Student('John'), Student('Sam')
patrick, michael, bill = Student('Patrick'), Student('Michael'), Student('Bill')
klass1 = ClassRoom([john, sam])
klass2 = ClassRoom([patrick, michael, bill])
def where_is(student, klasses):
return next((x for x in klasses if student in x.students), None)
assert klass1 is where_is(john, [klass1, klass2])
assert klass2 is where_is(patrick, [klass1, klass2])
nobody = Student('foo')
assert None is where_is(nobody, [klass1, klass2])
对于屈服版本,只需省略next
并返回生成器:
def where_is(student, klasses):
return (x for x in klasses if student in x.students)
for klass in where_is(john, [klass1, klass2]):
print klass
答案 2 :(得分:0)
所以这没有那么多的嵌套。基本上我们建立了一个字典m,它将每个学生映射到教室。在我看来,这不是那么可读或干净。
您可能想要构建一次字典,然后使用它来查找学生类。我强烈建议您查看models in Django。他们以更清洁的方式做你想要的事。 Django有什么好处,如果你把一个外键关系放在课堂上给学生,它会自动为学生对象添加方法,让你查找他们的课堂。所以它为你做了所有工作。
from itertools import chain
def flatten(items):
return list(chain.from_iterable(items))
def get_classroom_by_student(klasses, student_name):
m = flatten([dict.fromkeys(k.students, k).items() for k in klasses])
m = dict([(s.name, c) for s,c in m])
return m[student_name]