Python面向对象编程¶
概要: Python中的类、示例、属性、对象和方法
创建时间: 2022.10.02 11:31:56
更新时间: 2022.10.02 11:36:49
基本概念¶
类与对象的关系¶
一个类(Class)能够创建一种新的类型(Type),其中对象(Object)就是类的实例(Instance)
类的属性¶
对象可以使用属于它的普通变量来存储数据。这种从属于对象或者类的变量叫做字段(Field)。对象还可以使用属于类的函数来实现某些功能,这种函数叫做类的方法(Method)。字段与方法通称类的属性(Attribute)
字段由两种类型:它们属于某一类的各个实例或对象,称为实例变量(Instance Variables);或者从属于某一类本身,称为类变量(Class Variables)
self¶
类方法与普通函数的区别在于,类方法必须有一个额外的名字,且这个名字必须添加到参数列表的开头,但是不用在调用这个功能时为这个参数赋值,这种特定的变量引用对象本身,习惯上赋予self
这一名称(类似于C/C++语言中的指针)
举例来说,假设我们由一个MyClass
的类,这个类下有一个实例myobject
,当我们调用一个这个对象的方法时,如myobject.method(arg1, arg2)
时,Python将会自动将其转换成MyClass.method(myobject, arg1, arg2)
,这就是self
的意义所在
类¶
示例程序块如下
运行结果如下Text Only | |
---|---|
提示
在上述示例中,首先使用class
来创建一个新类,缩进的语句块代表这个类的主体,此处空代码块用pass
语句标明。接着,通过采用类的名称后面跟着一对括号的方法,给这个类创建了一个对象。为了验证操作是否成功,我们通过直接将它们打印出来来确认变量类型。结果显示我们在Person
类的__main__
模块中拥有了一个实例。
方法¶
类与对象一般都可以带有方法(Method),唯一的不同在于需要一个额外的self
变量。
示例程序块如下
Python | |
---|---|
Text Only | |
---|---|
提示
-
代码块中的
p = Person()
和p.say_hi()
等价于Person().sayhi()
-
sayhi()
这一方法不需要参数,但是在函数定义中依然有self
变量
__init__
方法¶
__init__
方法在类的对象被实例化(Instantiated)时立即运行,此外这一方法可以对任何想要进行操作的目标对象进行初始化(Initialization)操作
示例程序块如下
Python | |
---|---|
Text Only | |
---|---|
提示
-
上述实例中,我们定义
__init__
方法来接收name
参数,同时我们也创建了一个名为name
的字段 -
虽然有着两个
name
,但它们是不同的变量 -
self.name
表示这个name
是self
对象的一部分,另一个name
是一个局部变量
类变量与对象变量¶
前面几个小节谈论了类与对象的功能部分(方法),现在讨论数据部分,即字段,只不过是绑定(Bound)到类与对象的命名空间(Namespace)的普通变量
字段(Field)由两种类型——类变量与对象变量,它们根据究竟是类还是对象拥有这些变量来进行分类。
- 类变量(Class Variable)是共享的(Shared)——它们可以被属于该类的所有实例访问;
- 对象变量(Object Variable)由类的每一个独立的对象或者实例所拥有,不会被分享。
示例程序块如下
运行结果如下
提示
-
population
属于Robot
类,属于类变量,而name
属于一个对象(使用self
分配),属于对象变量 -
我们对于
name
对象变量采用self.name
标记法加以称呼,这是这个对象中所具有的方法 -
当一个对象变量与一个类变量名称相同时,类变量将会被隐藏
-
how_many
是一个属于类而非属于对象的方法,这就是说,我们可以把它定义为一个classmethod
(类方法)或者是staticmethod
(静态方法),这取决于我们是否知道我们属于哪个类,上例中由于已经引用了一个类变量,因此使用classmehod
(类方法) -
上例中,我们使用了装饰器(Decorator)将
how_many
方法标记为类方法,启用@classmethod
装饰器等价于调用how_many = classmethod(how_many)
-
只能使用
self
来引用同一对象的变量与方法,称为属性引用(Attribute Reference) -
所有的类成员都是公开的,但有一个例外:若使用数据成员并在其名字中使用了双下划线作为前缀,形成了诸如
__privatevar
的形式,Python会使用名称调整(Name-mangling)来使其称为一个私有变量
所有类成员(包括数据成员)都是公开的,并且Python中所有的方法都是虚拟的(Virtual)
继承¶
面向对象编程的一大优点就是对于代码的重用(Reuse),重用的一种实现方式是通过继承(Inheritance)机制,继承是在类之间实现类型与子类型(Type and Subtype)关系的工具。
举一个学校的例子:教师和学生都是学校的成员,他们有着公共的特征(姓名,年龄,地址),但是教师有独自的特征(薪水,课程,假期),学生也有独自的特征(成绩,学费)。如果创建两个独立的类,会显得太啰嗦,所以我们选择先创建一个公共类叫做SchoolMember
,然后让教师和学生从这个类中继承(Inherit),即他们成为子类,接着我们就可以向子类型中添加某些类独有的特征。
这样做有以下的优点
- 如果我们增加或者修改了
SchoolMember
的任何功能,那么它将自动反映在子类型中; - 我们可以将某一老师或者学生对象看作是
SchoolMember
的对象并加以引用(这在诸如清点学校成员数量时候很有用);
以上被称为多态性(Polymorphism),在任何情况下,只要父类型希望,子类型都可以被替换,即该对象可以看作是父类的实例。
在上文中,SchoolMemmber
类被称为基类(Base Class)或者超类(Superclass),Teacher
和Student
被称为派生类(Derived Classes)或者子类(Subclass)
示例程序块如下
Text Only | |
---|---|
提示
-
若要使用继承,在定义类时我们需要在类后面跟一个包含基类名称的元祖
-
注意到基类的
__init__
方法是通过self
变量被显式调用,因而我们可以初始化对象的基类的部分 -
由于我们在
Teacher
和Student
子类中定义了__init__
方法,所以Python不会自动调用基类SchoolMember
的构造函数,若果要使用的话,必须要显式地调用它 -
另一方面,如果我们没有在一个子类中定义一个
__init__
方法,Python将会自动调用基类的构造函数 -
当我们使用
SchoolMember
类的tell
方法时,我们可以将Teacher
或者Student
的实例看作是SchoolMember
的实例 -
当我们调用
tell
方法时,会调用子类的而不是基类的。原因在于Python总会从当前的世纪类型中开始寻找方法。如果它找不到对应的方法,它就会在该类所属的基类中按顺序逐个寻找属于基类的方法,而这个基类是定义子类时,后面所跟的元祖所指定的 -
如果继承元祖(Inheritance Tuple)中有超过一个类,这种情况被称为多重继承(Multiple Inheritance)。
8.end
参数用在超累的tell()
方法的print
函数中,目的在于打印一行并允许下一次打印在同一行继续(这是一个让print
能够不在打印的末尾打印出\n
的方法)
Python是高度面向对象的。