Python类结构和继承

Python类结构和继承,python,Python,我对Python非常陌生,我正在尝试解决类和继承等之间的关系 假设我有一个班学生: class Student(): def __init__(self, name): self.name = name def get_name(self): return self.name def set_name(self, name): self.name = name 该学生可以参加多种课程: class Course():

我对Python非常陌生,我正在尝试解决类和继承等之间的关系

假设我有一个班
学生

class Student():
    def __init__(self, name):
        self.name = name

    def get_name(self):
        return self.name

    def set_name(self, name):
        self.name = name
该学生可以参加多种课程:

class Course():
     def __init__(self, title):
         self.title = title

     def get_title(self):
         return self.title

     def set_title(self, title):
         self.title = title
对于每门课程,也可以有多个学生。 所以这是一种
manytomy
关系。 我的第一个想法是创建第三个类,名为
StudentCourse

class StudentCourse(Student, Course):

     student_courses = {}

     def __init__(self, student, course):
         self.student = student
         self.course = course

     def add_student_to_course(self, student, course, results):
         self.student_courses[student] = {
             'course': course,
             'results': results
         }

     def get_student_courses(self, student):
         return self.student_courses.get(student)
这是正确的结构吗? 如果是这样,我的问题是:在学生课堂中,我如何访问包含特定学生课程和结果的
学生课程
词典

编辑 我希望能够看到哪些学生参加了一门特定的课程,以及每个参加课程的学生的成绩


期待您的回复。

用继承来表达学生与课程之间的关系几乎肯定是错误的。继承表示IS-A关系。你的学生既不是课程,也不是你的课程的学生。所以IS-A是错误的

你可能想要的是HAS-A。每个
学生
都有许多他们注册的
课程。同样,每个
课程
都有几个
学生
注册。在数据库中,您可以创建关系对象来处理多对多关系,但在Python代码中,您可以使用数据结构。列表是一种自然选择。这是一个为每个学生添加课程列表和为每个课程添加学生列表的设计:

class Student:
    def __init__(self, name):
        self.name = name
        self.courses = []

    def enroll(self, course):
        self.courses.append(course)
        course.students.append(self)

class Course():
    def __init__(self, title):
        self.title = title
        self.students = []

    def enroll_student(self, student):
        student.enroll(self)

关于getter和setter的注意事项(与您的主要问题无关):您通常不需要在Python中编写像
get\u name
set\u name
这样的方法。通常,如果这些方法没有做任何事情(比如验证输入或以某种方式转换输出),您应该直接使用属性。在其他语言中,即使您还不需要这些方法,也总是编写和使用这些方法通常是最佳实践,但在Python中,如果您以后决定确实需要进行一些验证,您可以使用
属性将属性查找的实现更改为方法调用
继承几乎肯定是表达
学生
课程
之间关系的错误方式。继承表示IS-A关系。你的学生既不是课程,也不是你的课程的学生。所以IS-A是错误的

你可能想要的是HAS-A。每个
学生
都有许多他们注册的
课程。同样,每个
课程
都有几个
学生
注册。在数据库中,您可以创建关系对象来处理多对多关系,但在Python代码中,您可以使用数据结构。列表是一种自然选择。这是一个为每个学生添加课程列表和为每个课程添加学生列表的设计:

class Student:
    def __init__(self, name):
        self.name = name
        self.courses = []

    def enroll(self, course):
        self.courses.append(course)
        course.students.append(self)

class Course():
    def __init__(self, title):
        self.title = title
        self.students = []

    def enroll_student(self, student):
        student.enroll(self)

关于getter和setter的注意事项(与您的主要问题无关):您通常不需要在Python中编写像
get\u name
set\u name
这样的方法。通常,如果这些方法没有做任何事情(比如验证输入或以某种方式转换输出),您应该直接使用属性。在其他语言中,即使您还不需要这些方法,也总是编写和使用这些方法通常是最佳实践,但在Python中,如果您以后决定确实需要进行一些验证,您可以使用
属性将属性查找的实现更改为方法调用

这更像是一个基于意见的问题,而不是可以得到明确答案的问题。也就是说,鉴于
学生
课程
是两个完全不同的实体,仅通过所有权连接,因此没有必要在这两个实体中创建一个混合类

相反,我建议让他们以双链接的方式处理他们在多对多关系中的角色,即当你将
学生
添加到
课程
时,你也会通知
学生
他们现在是该课程的一部分,反之亦然。比如:

class Student(object):

    def __init__(self, name):
        self.name = name
        self.courses = {}  # we'll use a dict so that our courses can be mapped to results

    def add_course(self, course):
        if course not in self.courses:
            self.courses[course] = {}  # initialize each course with an empty dict
            # feel free to use any fields you like, like results etc.
            course.add_student(self)

    def del_course(self, course):
        self.courses.pop(course, None)
        course.del_student(self)

    def __repr__(self):  # just to ease our printouts
        return self.name
以及:

然后您可以在两个方向上使用它们来建立多对多关系,例如:

# Create some students and courses
john = Student("John Doe")
jane = Student("Jane Doe")
foo = Course("Foo Course")
bar = Course("Bar Course")
然后:

# initial state
print("John courses: {}".format(john.courses))  # John courses: {}
print("Jane courses: {}".format(jane.courses))  # Jane courses: {}
print("Foo students: {}".format(foo.students))  # Foo students: set([])
print("Bar students: {}".format(bar.students))  # Bar students: set([])

# lets add John to Foo:
john.add_course(foo)
print("John courses: {}".format(john.courses))  # John courses: {Foo Course: {}}
print("Foo students: {}".format(foo.students))  # Foo students: set([John Doe])

# lets add Jane to Bar, the other way around
bar.add_student(jane)
print("Jane courses: {}".format(jane.courses))  # Jane courses: {Bar Course: {}}
print("Bar students: {}".format(bar.students))  # Bar students: set([Jane Doe])

# lets add John to Bar as well
bar.add_student(john)
print("John courses: {}".format(john.courses))
# John courses: {Foo Course: {}, Bar Course: {}}
print("Bar students: {}".format(bar.students))
# Bar students: set([Jane Doe, John Doe])

# finally, lets add some info for the Foo course to John
john.courses[foo]["results"] = 94
print("John courses: {}".format(john.courses))
# John courses: {Foo Course: {'results': 94}, Bar Course: {}}
考虑到我们使用本机结构(集合和字典)来保存关系,我们不仅可以自动防止重复条目,还可以轻松(非常快速)检查关系,例如:

print("John is in Bar: {}".format(john in bar.students))  # John is in Bar: True
# or:
print("Bar is in John's courses: {}".format(bar in john.courses))
# Bar is in John's courses: True

print("Jane is in Foo: {}".format(jane in foo.students))  # Jane is in Foo: False

然后您可以扩展它,例如,将存储的结果和类似的结构形式化—您可以继续开发API以满足您的需要。祝你好运

这更多的是一个基于观点的问题,而不是一个你可以得到明确答案的问题。也就是说,鉴于
学生
课程
是两个完全不同的实体,仅通过所有权连接,因此没有必要在这两个实体中创建一个混合类

相反,我建议让他们以双链接的方式处理他们在多对多关系中的角色,即当你将
学生
添加到
课程
时,你也会通知
学生
他们现在是该课程的一部分,反之亦然。比如:

class Student(object):

    def __init__(self, name):
        self.name = name
        self.courses = {}  # we'll use a dict so that our courses can be mapped to results

    def add_course(self, course):
        if course not in self.courses:
            self.courses[course] = {}  # initialize each course with an empty dict
            # feel free to use any fields you like, like results etc.
            course.add_student(self)

    def del_course(self, course):
        self.courses.pop(course, None)
        course.del_student(self)

    def __repr__(self):  # just to ease our printouts
        return self.name
以及:

然后您可以在两个方向上使用它们来建立多对多关系,例如:

# Create some students and courses
john = Student("John Doe")
jane = Student("Jane Doe")
foo = Course("Foo Course")
bar = Course("Bar Course")
然后:

# initial state
print("John courses: {}".format(john.courses))  # John courses: {}
print("Jane courses: {}".format(jane.courses))  # Jane courses: {}
print("Foo students: {}".format(foo.students))  # Foo students: set([])
print("Bar students: {}".format(bar.students))  # Bar students: set([])

# lets add John to Foo:
john.add_course(foo)
print("John courses: {}".format(john.courses))  # John courses: {Foo Course: {}}
print("Foo students: {}".format(foo.students))  # Foo students: set([John Doe])

# lets add Jane to Bar, the other way around
bar.add_student(jane)
print("Jane courses: {}".format(jane.courses))  # Jane courses: {Bar Course: {}}
print("Bar students: {}".format(bar.students))  # Bar students: set([Jane Doe])

# lets add John to Bar as well
bar.add_student(john)
print("John courses: {}".format(john.courses))
# John courses: {Foo Course: {}, Bar Course: {}}
print("Bar students: {}".format(bar.students))
# Bar students: set([Jane Doe, John Doe])

# finally, lets add some info for the Foo course to John
john.courses[foo]["results"] = 94
print("John courses: {}".format(john.courses))
# John courses: {Foo Course: {'results': 94}, Bar Course: {}}
考虑到我们使用本机结构(集合和字典)来保存关系,我们不仅可以自动防止重复条目,还可以轻松(非常快速)检查关系,例如:

print("John is in Bar: {}".format(john in bar.students))  # John is in Bar: True
# or:
print("Bar is in John's courses: {}".format(bar in john.courses))
# Bar is in John's courses: True

print("Jane is in Foo: {}".format(jane in foo.students))  # Jane is in Foo: False

然后您可以扩展它,例如,将存储的结果和类似的结构形式化—您可以继续开发API以满足您的需要。祝你好运

你有没有一个例子来说明你是如何尝试使用它的?通常你会保留一份我喜欢的课程列表