在本章中,我们将介绍以下主题:
- 面向对象编程
- 在 GUI 中使用类
- 使用单一继承
- 使用多级继承
- 使用多重继承
Python 支持面向对象编程(OOP。面向对象支持可重用性;也就是说,以前编写的代码可以重用以生成大型应用,而不是从头开始。OOP 中的术语对象是指一个类的变量或实例,其中类是由方法和变量组成的结构的模板或蓝图。类中的变量称为数据成员,方法称为成员函数。创建类的实例或对象时,对象会自动访问数据成员和方法。
class
语句用于创建类。以下是创建类的语法:
class class_name(base_classes):
statement(s)
这里,class_name
是标识类的标识符。class
语句之后是构成类主体的语句。class
主体由该类中定义的不同方法和变量组成。
您可以创建单个类或继承另一个类的类。被继承的类称为基类。语法中class_name
之后的base_classes
参数表示该类将继承的所有基类。如果有多个基类,则它们需要用逗号分隔。被继承的类称为超类或基类,继承类称为派生类或子类。派生类可以使用基类的方法和变量,从而实现可重用性:
class Student:
name = ""
def __init__(self, name):
self.name = name
def printName(self):
return self.name
在本例中,Student
是一个包含名为name
的属性的类,该属性被初始化为 null。
class
语句会自动将某些值分配给某些固定的类属性。这些类属性可用于获取有关该类的信息。类属性列表如下所示:
__name__
:此属性表示class
语句中使用的类名__bases__
:此属性表示class
语句中提到的基类名称__dict__
:表示其他类属性的 dictionary 对象__module__
:该属性表示定义类的模块名称
一个类可以有任意数量的方法,每个方法可以有任意数量的参数。方法中始终定义一个必需的第一个参数,该第一个参数通常命名为self
(尽管您可以为该参数指定任何名称)。self
参数引用调用该方法的类的实例。在类中定义方法的语法如下所示:
class class_name(base_classes):
Syntax:
variable(s)
def method 1(self):
statement(s)
[def method n(self):
statement(s)]
类可以具有以下两种类型的数据成员:
- 类变量:这些是所有实例都可以共享的变量,任何一个实例对这些变量所做的更改也可以被其他实例看到。这些是在类的任何方法之外定义的数据成员。
- 实例变量:这些在方法内部定义的变量只属于对象的当前实例,称为实例变量。任何实例对实例变量所做的更改仅限于该特定实例,不会影响其他实例的实例变量。
让我们看看如何创建实例方法以及如何使用它来访问类变量。
要访问类变量,类变量必须以类名作为前缀。例如,要访问Student
类的name
类变量,需要按如下方式访问:
Student.name
您可以看到,name
类变量的前缀是Student
类名称。
要使用任何类的变量和方法,我们需要创建它的对象或实例。类的实例获取自己的变量和方法副本。这意味着一个实例的变量不会干扰另一个实例的变量。我们可以根据需要创建任意多个类实例。要创建类的实例,您需要编写类名,后跟参数(如果有)。例如,下面的语句创建了一个名为studentObj
的Student
类实例:
studentObj=Student()
您可以创建任意数量的Student
类实例。例如,以下行创建了Student
类的另一个实例:
courseStudent=Student()
现在,实例可以访问类的 class 属性和方法。
定义方法时需要明确指定self
。调用方法时,self
不是必需的,因为 Python 会自动添加它。
为了定义类的变量,我们从__init__()
方法获得帮助。__init__()
方法类似于传统 OOP 语言中的构造函数,是创建实例后执行的第一个方法。它用于初始化类的变量。取决于__init__()
方法在类中的定义方式,即有无参数,参数可能传递给__init__()
方法,也可能不传递给__init__()
方法。
如前所述,每个类方法的第一个参数都是一个名为self
的类实例。在__init__()
方法中,self
是指新创建的实例:
class Student:
name = ""
def __init__(self):
self.name = "David"
studentObj=Student()
在上例中,studentObj
实例是正在创建的Student
类的实例,其类变量将初始化为David
字符串。
甚至参数也可以传递给__init__()
方法,如下例所示:
class Student:
name = ""
def __init__(self, name):
self.name = name
studentObj=Student("David")
在前面的示例中,创建了studentObj
实例,并将David
字符串传递给它。该字符串将被分配给__init__()
方法中定义的name
参数,该参数反过来将用于初始化实例的类变量name
。记住,__init__()
方法不能返回值。
与类变量一样,类的实例可以访问该类的方法,然后是方法名称,中间有一个句点(.
。假设Student
类中有printName()
方法,可以通过studentObj
实例访问,语句如下:
studentObj.printName()
通过 GUI 从用户接收的数据可以通过使用简单变量直接处理,处理后的数据只能通过变量显示。但是,为了使数据保持结构化格式并获得 OOP 的好处,我们将学习以类的形式保存数据。也就是说,用户通过 GUI 访问的数据可以分配给类变量,通过类方法进行处理和显示。
让我们创建一个应用,它将提示用户输入名称,在输入名称后单击按钮,应用将显示一条 hello 消息以及输入的名称。用户输入的名称将分配给一个类变量,并且还将通过调用该类的 class 方法生成 hello 消息。
本配方的重点是了解用户输入的数据如何分配给类变量,以及如何通过类方法访问显示的消息。让我们基于无按钮对话框模板创建一个新的应用,并执行以下步骤:
- 将两个标签小部件、一个行编辑小部件和一个按钮小部件拖放到表单上。
- 将第一个标签小部件的文本属性设置为
Enter your name
。
Let's not change the text property of the second Label widget and keep its text property to its default value of TextLabel. This is because its text property will be set through code to display the hello message.
- 将按钮小部件的文本属性设置为
Click
。 - 将行编辑小部件的 objectName 属性设置为
lineEditName
。 - 将标签小部件的 objectName 属性设置为
labelResponse
。 - 将按钮小部件的 objectName 属性设置为
ButtonClickMe
。 - 使用名称
LineEditClass.ui
保存应用。应用将显示在以下屏幕截图中:
使用 Qt Designer 创建的用户界面存储在一个.ui
文件中,该文件是一个 XML 文件,需要转换为 Python 代码。
- 要进行转换,需要打开命令提示符窗口,导航到保存文件的文件夹,然后发出以下命令行:
C:\Pythonbook\PyQt5>pyuic5 LineEdit.uiClass -o LineEditClass.py
生成的 Python 脚本LineEditClass.py
可以在本书的源代码包中看到。
- 将前面的代码视为头文件,并将其导入到将从中调用其用户界面设计的文件中。
- 创建另一个名为
callLineEditClass.pyw
的 Python 文件,并将LineEditClass.py
代码导入其中:
import sys
from PyQt5.QtWidgets import QDialog, QApplication
from LineEditClass import *
class Student:
name = ""
def __init__(self, name):
self.name = name
def printName(self):
return self.name
class MyForm(QDialog):
def __init__(self):
super().__init__()
self.ui = Ui_Dialog()
self.ui.setupUi(self)
self.ui.ButtonClickMe.clicked.connect(self.dispmessage)
self.show()
def dispmessage(self):
studentObj=Student(self.ui.lineEditName.text())
self.ui.labelResponse.setText("Hello
"+studentObj.printName())
if __name__=="__main__":
app = QApplication(sys.argv)
w = MyForm()
w.show()
sys.exit(app.exec_())
在LineEditClass.py
文件中,使用Ui_ prepended
创建了一个名为顶级对象的类。也就是说,对于顶级对象Dialog
,创建了Ui_Dialog
类,并存储了我们小部件的接口元素。该类有两种方法,setupUi()
和retranslateUi()
。setupUi()
方法创建用于在 Qt Designer 中定义用户界面的小部件。此外,小部件的属性在该方法中设置。setupUi()
方法只接受一个参数,它是应用的顶级小部件,是QDialog
的一个实例。retranslateUi()
方法转换接口。
在callLineEditClass.py
文件中,您可以看到定义了一个名为Student
的类。Student
类包括一个名为name
的类变量和以下两种方法:
__init__()
:取强制self
参数和name
参数的构造函数,用于初始化name
类变量printName
:此方法只返回名称类变量中的值
按钮小部件的clicked()
事件连接到dispmessage()
方法;在 Line Edit 小部件中输入名称后,当用户单击按钮时,dispmessage()
方法将被调用。dispmessage()
方法通过名称studentObj
定义Student
类的对象,并将用户在行编辑小部件中输入的名称作为参数传递。因此,将调用Student
类的构造函数,并将用户输入的名称传递给构造函数。在行编辑小部件中输入的名称将分配给类变量name
。之后,名为labelResponse
的标签小部件被设置为显示字符串Hello
,并调用Student
类的printName
方法,该方法返回分配给 name 变量的字符串。
因此,单击按钮时,标签小部件将被设置为显示字符串Hello
,后跟用户在行编辑框中输入的名称,如以下屏幕截图所示:
我们还可以在类中使用两个或多个类属性。
假设除了类名Student
之外,我们还想向类中添加学生代码。在这种情况下,我们需要向类添加一个属性code
,以及一个getCode()
方法,该方法将访问指定的学生代码。除了类之外,GUI 也将改变。
我们需要在应用中再添加一个标签小部件和一个行编辑小部件,然后用另一个名称demoStudentClass
保存它。添加标签和行编辑小部件后,用户界面将显示如下屏幕截图所示:
用户界面文件demoStudentClass.ui
需要转换为 Python 代码。生成的 Python 脚本demoStudentClass.py
可以在本书的源代码包中看到。
让我们创建另一个名为callStudentClass.pyw
的 Python 文件,并将demoStudentClass.py
代码导入其中。callStudentClass.pyw
中的代码如下:
import sys
from PyQt5.QtWidgets import QDialog, QApplication
from demoStudentClass import *
class Student:
name = ""
code = ""
def __init__(self, code, name):
self.code = code
self.name = name
def getCode(self):
return self.code
def getName(self):
return self.name
class MyForm(QDialog):
def __init__(self):
super().__init__()
self.ui = Ui_Dialog()
self.ui.setupUi(self)
self.ui.ButtonClickMe.clicked.connect(self.dispmessage)
self.show()
def dispmessage(self):
studentObj=Student(self.ui.lineEditCode.text(),
self.ui.lineEditName.text())
self.ui.labelResponse.setText("Code:
"+studentObj.getCode()+", Name:"+studentObj.getName())
if __name__=="__main__":
app = QApplication(sys.argv)
w = MyForm()
w.show()
sys.exit(app.exec_())
在前面的代码中,您看到定义了一个名为Student
的类。Student
类包括两个名为name
和code
的类变量。Student
类除了两个类变量外,还包括以下三种方法:
__init__()
:取强制self
参数和两个参数code
和name
的构造函数,用于初始化两个类变量code
和name
getCode()
:此方法只返回code
类变量中的值getName()
:此方法只返回name
类变量中的值
按钮小部件的clicked()
事件连接到dispmessage()
方法;在 Line Edit 小部件中输入代码和名称后,当用户单击按钮时,dispmessage()
方法将被调用。dispmessage()
方法通过名称studentObj
定义Student
类的对象,并将用户在行编辑小部件中输入的代码和名称作为参数传递。将调用Student
类的构造函数__init__()
,并将用户输入的代码和名称传递给它。输入的代码和名称将分别分配给类变量 code 和 name。之后,名为labelResponse
的标签小部件被设置为显示通过Student
类的studentObj
对象调用getCode
和getName
两种方法输入的代码和名称。
因此,单击按钮后,标签小部件将在两行编辑小部件中显示用户输入的代码和名称,如以下屏幕截图所示:
继承是一个概念,通过这个概念,一个现有类的方法和变量可以被另一个类重用,而无需重新编码。也就是说,测试和运行的现有代码可以立即在其他类中重用
以下是三种类型的继承:
- 单继承:一个类继承另一个类
- 多级继承:一个类继承另一个类,而另一个类又被另一个类继承
- 多重继承:一个类继承两个或多个类
单一继承是最简单的继承类型,其中一个类派生自另一个单一类,如下图所示:
类B继承类A。这里,类A称为超类或基类,类B称为派生类或子类。
下面的语句定义了Marks
类继承Student
类的单一继承:
class Marks(Student):
在前面的语句中,Student
是基类,Marks
是派生类。因此,Marks
类的实例可以访问Student
类的方法和变量。
为了通过一个正在运行的示例理解单一继承的概念,让我们创建一个应用,该应用将提示用户输入学生的代码、姓名、历史和地理标记,并在单击按钮时显示它们。
用户输入的代码和名称将分配给名为Student
的类的类成员。历史和地理分数将分配给另一个名为Marks
的班级成员。
为了访问代码和名称,以及历史和地理标记,Marks
类将继承Student
类。通过继承,Marks
类的实例将访问并显示Student
类的代码和名称。
通过执行以下步骤,启动 Qt Designer 并基于对话框(不带按钮)模板创建新的应用:
- 在应用中,将五个标签小部件、四行编辑小部件和一个按钮小部件拖放到表单上。
- 将四个标签小部件的文本属性设置为
Student Code
、Student Name
、History Marks
和Geography Marks
。 - 删除第五个标签小部件的文本属性,因为它的文本属性将通过代码设置以显示代码、名称、历史和地理标记。
- 将按钮小部件的文本属性设置为
Click
。 - 将四行编辑小部件的 objectName 属性设置为
lineEditCode
、lineEditName
、lineEditHistoryMarks
和lineEditGeographyMarks
。 - 将标签小部件的 objectName 属性设置为
labelResponse
,将按钮小部件的 objectName 属性设置为ButtonClickMe
。 - 使用名称
demoSimpleInheritance.ui
保存应用。应用将显示如下屏幕截图所示:
用户界面文件demoSimpleInheritance.ui
是一个 XML 文件,使用pyuic5
实用程序将其转换为 Python 代码。您可以在本书的源代码包中找到生成的 Python 脚本demoSimpleInheritance.py
。前面的代码将用作头文件,并将导入另一个 Python 脚本文件,该脚本文件将调用demoSimpleInheritance.py
文件中定义的用户界面设计。
- 创建另一个名为
callSimpleInheritance.pyw
的 Python 文件,并将demoSimpleInheritance.py
代码导入其中。Python 脚本callSimpleInheritance.pyw
中的代码如下所示:
import sys
from PyQt5.QtWidgets import QDialog, QApplication
from demoSimpleInheritance import *
class Student:
name = ""
code = ""
def __init__(self, code, name):
self.code = code
self.name = name
def getCode(self):
return self.code
def getName(self):
return self.name
class Marks(Student):
historyMarks = 0
geographyMarks = 0
def __init__(self, code, name, historyMarks,
geographyMarks):
Student.__init__(self,code,name)
self.historyMarks = historyMarks
self.geographyMarks = geographyMarks
def getHistoryMarks(self):
return self.historyMarks
def getGeographyMarks(self):
return self.geographyMarks
class MyForm(QDialog):
def __init__(self):
super().__init__()
self.ui = Ui_Dialog()
self.ui.setupUi(self)
self.ui.ButtonClickMe.clicked.connect(self.dispmessage)
self.show()
def dispmessage(self):
marksObj=Marks(self.ui.lineEditCode.text(),
self.ui.lineEditName.text(),
self.ui.lineEditHistoryMarks.text(),
self.ui.lineEditGeographyMarks.text())
self.ui.labelResponse.setText("Code:
"+marksObj.getCode()+", Name:"+marksObj.getName()+"
nHistory Marks:"+marksObj.getHistoryMarks()+", Geography
Marks:"+marksObj.getGeographyMarks())
if __name__=="__main__":
app = QApplication(sys.argv)
w = MyForm()
w.show()
sys.exit(app.exec_())
在这段代码中,您可以看到定义了一个类,称为Student
。Student
类包括两个名为name
和code
的类变量,以及以下三种方法:
__init__()
:取强制self
参数和两个参数code
和name
的构造函数,用于初始化两个类变量code
和name
getCode()
:此方法只返回code
类变量中的值getName()
:此方法只返回name
类变量中的值
Marks
类继承Student
类。因此,Marks
类的实例不仅可以访问其自身的成员,还可以访问Student
类的成员。
Marks
类包括两个名为historyMarks
和geographyMarks
的类变量,以及以下三种方法:
__init__()
:取强制self
参数和四个参数code
、name
、historyMarks
、geographyMarks
的构造函数。在此构造函数中,将调用Student
类的构造函数,并将code
和name
参数传递给此构造函数。historyMarks
和geographyMarks
参数将用于初始化类成员historyMarks
和geographyMarks
。getHistoryMarks()
:此方法只返回historyMarks
类变量中的值。getGeographyMarks()
:此方法只返回geographyMarks
类变量中的值。
按钮的clicked()
事件连接到dispmessage()
方法。在 Line Edit 窗口小部件中输入代码、名称、历史和地理标记后,当用户单击按钮时,dispmessage()
方法将被调用。dispmessage()
方法通过名称marksObj
定义Marks
类的对象,并将用户在 Line Edit 小部件中输入的代码、名称、历史和地理标记作为参数传递。将调用Marks
类的构造函数__init__()
,并将用户输入的代码、名称、历史记录和地理标记传递给它。从Marks
类的构造函数调用Student
类的构造函数,并将code
和name
传递给该构造函数。code
和name
参数将分别分配给Student
类的code
和name
类变量。
同样,历史和地理标记将分别分配给Marks
类的historyMarks
和geographyMarks
类变量。之后,名为labelResponse
的标签小部件被设置为通过marksObj
对象调用getCode
、getName
、getHistoryMarks
和getGeographyMarks
四种方法来显示输入的代码、名称、历史和地理标记。由于使用继承,Marks
类的marksObj
对象获得了访问Student
类的getCode
和getName
方法的权限。
因此,点击按钮后,标签小部件将显示用户通过名为labelResponse
的标签小部件输入的代码、名称、历史标记和地理标记,如本屏幕截图所示:
多级继承是指一个类继承另一个类。继承类依次被第三个类继承,如下图所示:
在上图中,您可以看到类B继承类A和类C,依次继承类B。
下面的语句定义了多级继承,Result
类继承Marks
类,Marks
类继承Student
类:
class Student:
class Marks(Student):
class Result(Marks):
在前面的语句中,Student
是基类,Marks
类继承Student
类。Result
类继承Marks
类。因此,Result
类的实例可以访问Marks
类的方法和变量,Marks
类的实例可以访问Student
类的方法和变量。
为了理解多级继承的概念,让我们创建一个应用,它将提示用户输入学生的代码、姓名、历史分数和地理分数,并在单击按钮时显示总分数和百分比。总分为历史分和地理分之和。假设最高分数为 100,计算百分比的公式为:总分/200*100。
用户输入的代码和名称将分配给名为Student
的类的类成员。历史和地理分数将分配给另一个名为Marks
的班级成员。
为了访问代码和名称以及历史和地理标记,Marks
类将继承Student
类。
使用此多级继承,Marks
类的实例将访问Student
类的代码和名称。为了计算总分和百分比,使用了另一个类,称为Result
类。Result
类将继承Marks
类。因此,Result
类的实例可以访问Marks
类的类成员以及Student
类的类成员。Result
类有两个类成员totalMarks
和percentage
。totalMarks
类成员将被分配Marks
类的historyMarks
和geographyMarks
成员之和。百分比成员将被分配根据历史和地理分数获得的百分比。
总共有三个类,Student
、Marks
和Result
,其中Result
类继承Marks
类,Marks
类依次继承Student
类。因此,Result
类的成员可以访问Marks
类的类成员以及Student
类的类成员。以下是创建此应用的分步过程:
-
启动 Qt Designer 并基于对话框创建新的应用,而不使用按钮模板。
-
将六个标签小部件、六个行编辑小部件和一个按钮小部件拖放到表单上。
-
将六个标签小部件的文本属性设置为
Student Code
、Student Name
、History Marks
、Geography Marks
、Total
和Percentage
。 -
将按钮小部件的文本属性设置为
Click
。 -
将六行编辑小部件的 objectName 属性设置为
lineEditCode
、lineEditName
、lineEditHistoryMarks
、lineEditGeographyMarks
、lineEditTotal
和lineEditPercentage
。 -
将按钮小部件的 objectName 属性设置为
ButtonClickMe
。 -
通过从属性编辑器窗口取消选中 Enable 属性,禁用
lineEditTotal
和lineEditPercentage
框。lineEditTotal
和lineEditPercentage
小部件被禁用,因为这些框中的值将通过代码分配,我们不希望用户更改它们的值 -
使用名称
demoMultilevelInheritance.ui
保存应用。应用将显示在以下屏幕截图中:
用户界面文件demoMultilevelInheritance.ui
是一个 XML 文件,通过使用pyuic5
实用程序将其转换为 Python 代码。您可以在本书的源代码包中看到生成的 Python 脚本demoMultilevelInheritance.py
。demoMultilevelInheritance.py
文件将用作头文件,并将导入另一个 Python 脚本文件,该文件将使用在demoMultilevelInheritance.py
中创建的 GUI。
**9. 创建另一个名为callMultilevelInheritance.pyw
的 Python 文件,并将demoMultilevelInheritance.py
代码导入其中。Python 脚本callMultilevelInheritance.pyw
中的代码如下所示:
import sys
from PyQt5.QtWidgets import QDialog, QApplication
from demoMultilevelInheritance import *
class Student:
name = ""
code = ""
def __init__(self, code, name):
self.code = code
self.name = name
def getCode(self):
return self.code
def getName(self):
return self.name
class Marks(Student):
historyMarks = 0
geographyMarks = 0
def __init__(self, code, name, historyMarks,
geographyMarks):
Student.__init__(self,code,name)
self.historyMarks = historyMarks
self.geographyMarks = geographyMarks
def getHistoryMarks(self):
return self.historyMarks
def getGeographyMarks(self):
return self.geographyMarks
class Result(Marks):
totalMarks = 0
percentage = 0
def __init__(self, code, name, historyMarks,
geographyMarks):
Marks.__init__(self, code, name, historyMarks,
geographyMarks)
self.totalMarks = historyMarks + geographyMarks
self.percentage = (historyMarks +
geographyMarks) / 200 * 100
def getTotalMarks(self):
return self.totalMarks
def getPercentage(self):
return self.percentage
class MyForm(QDialog):
def __init__(self):
super().__init__()
self.ui = Ui_Dialog()
self.ui.setupUi(self)
self.ui.ButtonClickMe.clicked.connect(self.dispmessage)
self.show()
def dispmessage(self):
resultObj=Result(self.ui.lineEditCode.text(),
self.ui.lineEditName.text(),
int(self.ui.lineEditHistoryMarks.text()),
int(self.ui.lineEditGeographyMarks.text()))
self.ui.lineEditTotal.setText(str(resultObj.
getTotalMarks()))
self.ui.lineEditPercentage.setText(str(resultObj.
getPercentage()))
if __name__=="__main__":
app = QApplication(sys.argv)
w = MyForm()
w.show()
sys.exit(app.exec_())
在前面的代码中,在callMultilevelInheritance.pyw
文件中,您可以看到定义了一个名为Student
的类。Student
类包括两个名为name
和code
的类变量,以及以下三种方法:
__init__()
:取强制self
参数和两个参数code
和name
的构造函数,用于初始化两个类变量code
和name
getCode()
:此方法只返回code
类变量中的值getName()
:此方法只返回name
类变量中的值
Marks
类继承Student
类。因此,Marks
类的实例不仅可以访问其自身的成员,还可以访问Student
类的成员。
Marks
类包括两个名为historyMarks
和geographyMarks
的类变量,以及以下三种方法:
__init__()
:取强制self
参数和四个参数code
、name
、historyMarks
、geographyMarks
的构造函数。在此构造函数中,将调用Student
类的构造函数,并将code
和name
参数传递给此构造函数。historyMarks
和geographyMarks
参数将用于初始化historyMarks
和geographyMarks
类成员。getHistoryMarks()
:此方法只返回historyMarks
类变量中的值。getGeographyMarks()
:此方法只返回geographyMarks
类变量中的值。
Result
类继承Marks
类。Result
类的实例不仅可以访问自己的成员,还可以访问Marks
类和Student
类的成员。
Result
类包括两个类变量totalMarks
和percentage
,以及以下三种方法:
__init__()
:取强制self
参数和四个参数code
、name
、historyMarks
、geographyMarks
的构造函数。从该构造函数调用Marks
类的构造函数,并将code
、name
、historyMarks
和geographyMarks
参数传递给该构造函数。historyMarks
和geographyMarks
之和将分配给totalMarks
类变量。假设每个的最大分数为 100,历史和地理分数的百分比将被计算并分配给百分比类变量。getTotalMarks()
:此方法只返回historyMarks
和geographyMarks
类变量之和。getPercentage()
:此方法只返回历史和地理分数的百分比。
按钮小部件的clicked()
事件连接到dispmessage()
方法。在 Line Edit 窗口小部件中输入代码、名称、历史标记和地理标记后,当用户单击按钮时,dispmessage()
方法将被调用。dispmessage()
方法通过名称resultObj
定义Result
类的对象,并将用户在 Line Edit 小部件中输入的代码、名称、历史和地理标记作为参数传递。将调用Result
类的构造函数__init__()
,并将用户输入的代码、名称、历史标记和地理标记传递给它。从Result
类的构造函数调用Marks
类的构造函数,并将代码、名称、历史标记和地理标记传递给该构造函数。从Marks
类的构造函数调用Student
类构造函数,并向其传递code
和name
参数。在Student
类的构造函数中,code
和name
参数将分别分配给类变量code
和name
。同样,历史和地理标记将分别分配给Marks
类的historyMarks
和geographyMarks
类变量。
historyMarks
和geographyMarks
之和将分配给totalMarks
类变量。此外,历史和地理分数的百分比将被计算并分配给percentage
类变量。
之后,通过resultObj
调用getTotalMarks
方法,将名为lineEditTotal
的行编辑小部件设置为显示总分,即历史和地理标记的总和。此外,名为lineEditPercentage
的行编辑小部件被设置为通过resultObj
调用getPercentage
方法来显示标记的百分比。
因此,点击按钮后,名为lineEditTotal
和lineEditPercentage
的行编辑小部件将显示用户输入的总分数以及历史和地理分数的百分比,如以下屏幕截图所示:
多重继承是指一个类继承两个或多个类,如下图所示:
类C继承了类A和类B这两个类。
下面的语句定义了多级继承,其中Result
类继承Marks
类,Marks
类依次继承Student
类:
class Student:
class Marks:
class Result(Student, Marks):
在前面的语句中,Student
和Marks
是基类,Result
类继承Student
类和Marks
类。因此,Result
类的实例可以访问Marks
和Student
类的方法和变量。
为了实际理解多级继承的概念,让我们创建一个应用,它将提示用户输入学生的代码、姓名、历史分数和地理分数,并在单击按钮时显示总分数和百分比。总分为历史分和地理分之和。假设每个人的最高分数为 100,计算百分比的公式为:总分/200*100。
用户输入的代码和名称将分配给名为Student
的类的类成员。历史和地理分数将分配给另一个名为Marks
的班级成员。
为了访问代码和名称,以及历史和地理标记,Result
类将继承两个类,Student
类和Marks
类。通过这种多重继承,Result
类的实例可以访问Student
类的代码和名称,以及Marks
类的historyMarks
和geographyMarks
类变量。换句话说,Result
类的实例通过多重继承可以访问Marks
类的类成员,也可以访问Student
类的类成员。Result
类有两个类成员,totalMarks
和percentage
。totalMarks
类成员将被分配Marks
类的historyMarks
和geographyMarks
成员之和。百分比成员将被分配根据历史和地理分数获得的百分比。
让我们通过一个循序渐进的过程来了解如何将多级继承应用于三个类:Student
、Marks
和Result
。Result
类将继承Student
和Marks
两个类。这些步骤解释了Result
类的成员如何通过多级继承访问Student
和Marks
类的类成员:
-
启动 Qt Designer 并基于对话框创建新的应用,而不使用按钮模板。
-
在应用中,将六个标签小部件、六个行编辑小部件和一个按钮小部件拖放到表单上。
-
将六个标签小部件的文本属性设置为
Student Code
、Student Name
、History Marks
、Geography Marks
、Total
和Percentage
。 -
将按钮小部件的文本属性设置为
Click
。 -
将六行编辑小部件的 objectName 属性设置为
lineEditCode
、lineEditName
、lineEditHistoryMarks
、lineEditGeographyMarks
、lineEditTotal
和lineEditPercentage
。 -
将按钮小部件的 objectName 属性设置为
ButtonClickMe
。 -
通过从属性编辑器窗口取消选中 Enable 属性,禁用
lineEditTotal
和lineEditPercentage
框。lineEditTotal
和lineEditPercentage
框被禁用,因为这些框中的值将通过代码分配,我们不希望用户更改它们的值。 -
使用名称
demoMultipleInheritance.ui
保存应用。应用将显示在以下屏幕截图中:
用户界面文件demoMultipleInheritance .ui
是一个 XML 文件,使用pyuic5
实用程序将其转换为 Python 代码。您可以在本书的源代码包中找到生成的 Python 代码demoMultipleInheritance.py
。demoMultipleInheritance.py
文件将用作头文件,并将导入另一个 Python 脚本文件,该脚本文件将调用在demoMultipleInheritance.py
文件中创建的 GUI。
- 创建另一个名为
callMultipleInheritance.pyw
的 Python 文件,并将demoMultipleInheritance.py
代码导入其中:
import sys
from PyQt5.QtWidgets import QDialog, QApplication
from demoMultipleInheritance import *
class Student:
name = ""
code = ""
def __init__(self, code, name):
self.code = code
self.name = name
def getCode(self):
return self.code
def getName(self):
return self.name
class Marks:
historyMarks = 0
geographyMarks = 0
def __init__(self, historyMarks, geographyMarks):
self.historyMarks = historyMarks
self.geographyMarks = geographyMarks
def getHistoryMarks(self):
return self.historyMarks
def getGeographyMarks(self):
return self.geographyMarks
class Result(Student, Marks):
totalMarks = 0
percentage = 0
def __init__(self, code, name, historyMarks,
geographyMarks):
Student.__init__(self, code, name)
Marks.__init__(self, historyMarks, geographyMarks)
self.totalMarks = historyMarks + geographyMarks
self.percentage = (historyMarks +
geographyMarks) / 200 * 100
def getTotalMarks(self):
return self.totalMarks
def getPercentage(self):
return self.percentage
class MyForm(QDialog):
def __init__(self):
super().__init__()
self.ui = Ui_Dialog()
self.ui.setupUi(self)
self.ui.ButtonClickMe.clicked.connect(self.dispmessage)
self.show()
def dispmessage(self):
resultObj=Result(self.ui.lineEditCode.text(),
self.ui.lineEditName.text(),
int(self.ui.lineEditHistoryMarks.text()),
int(self.ui.lineEditGeographyMarks.text()))
self.ui.lineEditTotal.setText(str(resultObj.
getTotalMarks()))
self.ui.lineEditPercentage.setText(str(resultObj.
getPercentage()))
if __name__=="__main__":
app = QApplication(sys.argv)
w = MyForm()
w.show()
sys.exit(app.exec_())
在这段代码中,您可以看到定义了一个名为Student
的类。Student
类包括两个名为name
和code
的类变量,以及以下三种方法:
__init__()
:取强制self
参数和两个参数code
和name
的构造函数,用于初始化两个类变量code
和name
getCode()
:此方法只返回code
类变量中的值getName()
:此方法只返回name
类变量中的值
Marks
类包括两个类变量historyMarks
和geographyMarks
,以及以下三种方法:
__init__()
:取强制self
参数和两个参数historyMarks
和geographyMarks
的构造函数。historyMarks
和geographyMarks
参数将用于初始化historyMarks
和geographyMarks
类成员。getHistoryMarks()
:此方法只返回historyMarks
类变量中的值。getGeographyMarks()
:此方法只返回geographyMarks
类变量中的值。
Result
类继承Student
类和Marks
类。Result
类的实例不仅可以访问自己的成员,还可以访问Marks
类和Student
类的成员。
Result
类包括两个名为totalMarks
和percentage
的类变量,以及以下三种方法:
__init__()
:取强制self
参数和四个参数code
、name
、historyMarks
、geographyMarks
的构造函数。从该构造函数调用Student
类构造函数,并将code
和name
参数传递给该构造函数。另外,从这个构造函数中,Marks
类构造函数将被调用,historyMarks
和geographyMarks
参数将被传递给该构造函数。historyMarks
和geographyMarks
之和将分配给totalMarks
类变量。假设每项的最大分数为 100,历史和地理分数的百分比将被计算并分配给percentage
类变量。getTotalMarks()
:此方法只返回historyMarks
和geography
类变量之和。getPercentage()
:此方法只返回历史和地理分数的百分比。
按钮小部件的clicked()
事件连接到dispmessage()
方法。在 Line Edit 窗口小部件中输入代码、名称、历史标记和地理标记后,当用户单击按钮时,dispmessage()
方法将被调用。dispmessage()
方法通过名称resultObj
定义Result
类的对象,并将用户在行编辑小部件中输入的代码、名称、历史标记和地理标记作为参数传递。将调用Result
类的构造函数__init__()
,并将用户输入的代码、名称、历史标记和地理标记传递给它。从Result
类的构造函数调用Student
类构造函数和Marks
类构造函数。代码和名称将传递给Student
类构造函数,历史和地理标记将传递给Marks
类构造函数。
在Student
类构造函数中,代码和名称将分别分配给code
和name
类变量。类似地,在Marks
类构造函数中,历史和地理标记将分别分配给Marks
类的historyMarks
和geographyMarks
类变量。
historyMarks
和geographyMarks
之和将分配给totalMarks
类变量。此外,历史和地理分数的百分比将被计算并分配给percentage
类变量。
之后,通过resultObj
调用getTotalMarks
方法,将名为lineEditTotal
的行编辑小部件设置为显示总分,即历史和地理标记的总和。此外,名为lineEditPercentage
的行编辑小部件被设置为通过resultObj
调用getPercentage
方法来显示标记的百分比。
因此,点击按钮后,名为lineEditTotal
和lineEditPercentage
的行编辑小部件将显示用户输入的历史和地理标记的总分数和百分比,如以下屏幕截图所示: