在本教程中,您将掌握面向对象编程(OOPs)的基本概念。此外,您还将通过示例学习对象、如何定义类、什么是实例等内容。
Python作为一种多范式编程语言,允许开发者选择任何他希望的脚本编写方法,包括过程式、函数式、命令式和面向对象的风格。面向对象编程,通常缩写为OOPS,因其简易性和结构独特性而得到普遍接受。顾名思义,对象是OOPS概念的核心,与类一起。换句话说,面向对象编程语言的基础是对象和类。
面向对象编程是一种编程范式,它通过使用“对象”的概念来构建程序。对象的两个重要特性是属性和行为。
例如,一个学生可以是一个对象,其属性包括姓名、班级、学号等,其行为包括说话、唱歌、跳舞等。类似地,一部手机可以表示为一个对象,其属性包括名称、型号、颜色等,其行为包括打电话、发短信、上传、下载等。
在编程中,一个对象可以用来表示与代码相关的数据和方法。通过将属性和行为捆绑到单个对象中,OOPS方法有助于编写整洁且组织良好的代码。此外,它还通过实现代码重用性来减少冗余。这种专注于代码重用性的概念被称为“DRY”,即“不要重复代码”。
在深入细节之前,让我们看看面向对象编程与面向过程编程有何不同。
| 面向对象编程 | 面向过程编程。 |
|---|---|
| 处理数据 | 处理算法 |
| 程序被划分为对象 | 程序被划分为函数 |
| 遵循自下而上的方法 | 遵循自上而下的方法 |
| 对象可以在成员函数内自由移动 | 数据可以在程序内的函数之间移动 |
| 包含访问说明符,如私有、公共和受保护 | 不包含访问说明符 |
| 支持继承 | 不支持继承 |
| 支持重载 | 不支持重载 |
| 数据隐藏是可能的 | 数据隐藏是不可能的 |
| 需要更多内存 | 需要更少内存 |
| 高度安全 | 安全性较低 |
| 示例:C++、Java、Python 等 | 示例:C、FORTRAN、Pascal 等 |
在面向对象编程中,类是用户定义的数据结构,用于创建对象。用户可以在类中定义一组属性和函数(称为方法),这些属性和方法与对象相关联。类中的方法标识了在该类中创建的对象需要对其数据执行的行为和操作。简而言之,我们可以说类是对象的集合,或者是定义了共同属性和方法的对象的蓝图。
现在你已经很清楚什么是类了。接下来我们将学习如何定义一个类。
一个类的定义总是以关键字 class 开始,后面跟着 class_name 和一个冒号。类的主体在下面编写,并遵循缩进规则。
语法如下:
class Class_name:
. . . . . . . .
class_body
#Here you can define all attributes and methods
. . . . . . . .
本教程将教你创建一个名为Student的类,用于存储学生的一些基本特征,如姓名、年龄、学号以及学生可以拥有的品质。这里有一个例子
class Student:
#class attribute
Dept = 'Computer Science'
#instance attribute
def __init__(self,name,age):
self.name=name
self.age=age
现在,让我们仔细研究这个例子,以便更清楚地理解类的概念。在这个例子中,
__init__() 的初始化方法内部定义。该方法在对象创建时立即初始化实例属性。你可以向 .__init__ 方法传递任意数量的参数,但需要注意的是,第一个参数应始终是一个名为 self 的变量。self.name = name 表示创建了一个名为 name 的实例属性,并为其分配了参数值。self.age = age 表示创建了一个名为 age 的实例属性__init__() 方法之外声明。在我们的例子中,所有学生都属于计算机科学系。因此,Dept 在 __init__() 方法之前被声明为类属性。本质上,类属性用于定义所有类实例都具有相同值的属性,而实例属性用于定义每个类实例都具有唯一值的属性。
在 Python 中编写类时,必须注意缩进,因为缩进在构建程序中起着至关重要的作用。在上面的例子中,你可以看到每个组件的结构是多么清晰,以及如何保持缩进。
如果你未能使用正确的缩进,你将会收到一个 Indentation Error(缩进错误)。
那么我们现在已经定义了Student类。让我们创建一些学生,它们是这个类的对象。
对象,也称为实例,是类的实例化。更具体地说,对象意味着类的实例。
通过定义一个类,我们只创建了对象的描述。目前还没有分配内存或空间。要使其有意义,你需要实例化一个对象。这可以通过使用类名后跟括号来实现,括号中包含要传递给 __init__() 方法的值。
语法是 :
obj = Class_name() #S1 = Student()
其中 obj 是该类的一个对象。
现在考虑这样一种情况,在实例化对象时,你忘记提供要传递给 __init__() 方法的参数。Python 会简单地引发一个名为 TypeError 的错误,如下所示。
class Student:
#class attribute
Dept = 'Computer Science'
#instance attribute
def __init__(self,name,age):
self.name=name
self.age=age
S1 = Student()
S2 = Student()
输出错误
Traceback (most recent call last): File "oops_ex.py", line 11, inS1=Student() TypeError: __init__() missing 2 required positional arguments: 'name' and 'age'
为了避免这个错误,你需要在实例化对象时在括号内传递参数。下面的例子展示了这一点
class Student:
#class attribute
Dept = 'Computer Science'
#instance attribute
def __init__(self,name,age):
self.name=name
self.age=age
S1 = Student("Chris", 17)
S2 = Student("Debora",16)
在我们的例子中,S1 和 S2 是该类的两个实例。S1 是一个类的对象,包含两个属性 Chris 和 17。同样,S2 表示一个类的对象,包含两个属性 Debora 和 16。
从一个类中访问属性根本不是一件难事。访问可以通过使用点运算符和对象来完成。下面的例子展示了访问实例属性和类属性的方法。
类属性 Dept 是使用对象 S1 通过点运算符访问的,其输出结果为 Computer Science。
>>> print(S1.Dept)
Computer Science
同样,实例属性可以使用点运算符与对象一起访问。请参考下面的例子来理解这个概念。
class Student:
#class attribute
Dept = 'Computer Science'
#instance attribute
def __init__(self,name,age):
self.name=name
self.age=age
S1 = Student("Chris", 17)
S2 = Student("Debora",16)
print('Hi I am',S1.name,'and I am',S1.age,'years old')
print('Hi I am',S2.name,'and I am',S2.age,'years old')
输出
Hi I am Chris and I am 17 years old Hi I am Debora and I am 16 years old
在这里,S1.name 和 S1.age 表示通过点运算符访问实例 S1 的实例属性 name 和 age,这会产生结果 Chris 和 17。同样,S2.name 和 S2.age 访问实例 S2 的属性。
在面向对象编程中,我们可以通过添加新属性、更改属性值或删除属性本身来动态修改属性。
我们通过添加一个新属性 S1.idno = 10001 对我们的示例进行了轻微修改。当你观察这个例子时,你可以注意到新属性不是在类内部定义的,而是在外部动态定义的。
class Student:
Dept = 'Computer Science'
def __init__(self,name,age):
self.name=name
self.age=age
S1 = Student("Chris", 17)
S1.idno = 10001
print('Hi Iam',S1.name,'and Iam',S1.age,'years old holding idno:',S1.idno)
输出
Hi Iam Chris and Iam 17 years old holding idno: 10001
动态更改属性的值也是可能的。请看下面的程序,我们将 S1 的 .name 属性更改为 Tom,之前它被赋值为 Chris。以类似的方式,我们将类属性 Dept 从 Computer Science 修改为 Science。
class Student:
#class attribute
Dept = 'Computer Science'
#instance attribute
def __init__(self,name,age):
self.name=name
self.age=age
S1 = Student("Chris", 17)
S1.name ='Tom'
S1.Dept ='Science'
print('Hi I am',S1.name,'and I am',S1.age,'years old')
输出
Hi Iam Tom and Iam 17 years old. Science
关键点在于,默认情况下所有自定义对象都是可变的。具体来说,我们可以说可变对象可以动态地被改变,而不可变对象则不能。因此,列表和字典是可变的,而字符串和元组是不可变的。
你也可以使用 del 关键字后跟一个点运算符来删除一个属性。
S1.idno = 10001
del S1.idno
这里它删除了属性 id.no。
下面列出了 Python 中的内置属性。可以使用点表示法来访问它们,如下例所示。
class Student:
#class attribute
Dept = 'Computer Science'
#instance attribute
def __init__(self,name,age):
self.name=name
self.age=age
print("Student.__dict__:",Student.__dict__)
print("Student.__doc__:",Student.__doc__)
print("Student.__name__:",Student.__name__)
print("Student.__module__:",Student.__module__)
print("Student.__bases__:",Student.__bases__)
输出
Student.__dict__: {'__module__': '__main__', 'Dept': 'Computer Science', '__init__': , '__dict__': , '__weakref__': , '__doc__': None}
Student.__doc__: None
Student.__name__: Student
Student.__module__: __main__
Student.__bases__: (,)
面向对象编程支持在类中使用方法。实例方法可以被称为定义在类内部的函数,用于指定对象的行为。需要记住的关键点是,始终确保从该特定类的实例本身调用实例方法。此外,实例方法的第一个参数总是 self,就像在 .__init__() 方法中一样。
让我们通过仔细观察以下示例,看看如何创建一个实例方法。在我们的 Student 类中,我们有两个实例方法,即
class Student:
#class attribute
Dept = 'Computer Science'
#instance attribute
def __init__(self,name,age):
self.name=name
self.age=age
#instance Methods
def StudDetails(self):
print('Hi Iam',self.name,'and Iam',self.age,'years old. ')
def StudAct(self, activity):
print(self.name,'is good at',activity)
S1 = Student("Chris", 17)
S2 = Student('Debora',16)
S1.StudDetails() #calling instance method StudDetails()
S2.StudDetails()
S1.StudAct("Football") #calling instance method StudAct()
S2.StudAct('Tennis')
在这个例子中,定义了 StudDetails() 方法来打印学生的名字和年龄。 StudAct() 方法打印出特定学生擅长的活动。例如,当调用 S1.StudDetails() 方法时,控制权转移到类 Student 中定义的 StudDetails 函数,在那里它执行打印功能。StudDetails 中定义的参数是 self,它提供了在 .__init__() 方法中定义的值。因此,我们可以访问实例属性 .name 和 .age。最后,输出被打印为“嗨,我是克里斯,我17岁。”
同样,S1.StudAct("Football") 会输出“Chris is good at Football”,其中参数“Football”被传递给方法定义中的‘activity’参数。
输出
Hi Iam Chris and Iam 17 years old. Hi Iam Debora and Iam 16 years old. Chris is good at Football Debora is good at Tennis