Python 入门(五)- 面向对象(下)

类与对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
python 类
|- 变量
|- 类变量
|_ 实例变量
|- 方法
|- 类方法
|- 实例方法
|_ 静态方法
|- 构造函数
|- 成员可见性
|_ 面向对象三大特性
|- 继承性
|- 封装性
|_ 多态性

成员可见性

成员是具有内外之分的,如下例中student1.do_homework()就是外部调用,do_english_homework()是内部调用(在一个类中的方法内部调用另一个方法)。

所有成员都可以在外部访问,安全性无法得到保证。

1
2
3
4
5
6
7
8
9
10
11
12
class Student():
sum = 0 # 类变量

def do_homework(self):
self.do_english_homework() # 内部调用
print('homework')

def do_english_homework(self):
print('english homework')

student1 = Student('student1',18)
student1.do_homework() # 外部调用

举个例子,如下例中,学生的分数(score)不希望被外部更改,而只能通过内部的方法进行更改。

不应通过直接访问变量来修改变量值,推荐通过方法来进行更改。

python中没有类似publicprivate关键字,而是通过双下划线__来区分私有方法和私有属性。前后均有双下划线的方法不被认为是私有方法(例如__init__)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Student():
sum = 0 # 类变量

def __init__(self, name, age):
self.name = name
self.age = age
self.__score = 0 # 实例变量,初始值为0
self.__class__.sum += 1

def __marking(self, score):
self.score = score
print(self.name+'本次打分为:'+str(self.score))

student1 = Student('student1',18)
student1.__marking(59) # 外部调用方法进行打分,而不是直接修改变量值。此处会报错,无法在外部调用私有方法

student1.__score = -1 # 非私有变量,动态创建新的变量
print(student1._Student__score) # 0 读取私有变量
print(student1.__dict__) # {'name': 'student1', 'age': 18, '_Student__score': 0, 'score': 59, '__score': -1}
  • 私有变量可以从外部访问,私有方法无法从外部访问。
  • 私有变量之所以可以从外部读取,是因为 python 的动态变量特性,student1.__score = -1相当于新添加了一个实例变量,此处并不是self.__score = 0中定义的变量。
  • student1.__dict__ 打印出了 '_Student__score' 是将私有变量更名了(保护机制),正是因为私有变量更名,所以'__score': -1才可动态添加进去。
  • python 并没有提供一个机制完全保护了私有变量,因为可通过student1._Student__score来读取,但是一般情况下不要这么用。

面向对象三大特性

继承性

继承性的作用在于避免重复定义属性和方法。当子类继承父类,则具有了父类中的方法(构造函数)。

继承的写法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 父类
class Human():
sum = 0

def __init__(self, name, age):
self.name = name
self.age = age

def get_name(self):
print(self.name)

# 子类,继承Human类
class Student(Human):
def do_homework(self):
print('do homework')

print(Student.sum) # 0

student1 = Student('student1', 18)
print(student1.sum) # 0
print(student1.name) # student1
print(student1.age) # 18
student1.get_name() # student1

注:python可以多继承,即一个子类可以继承多个父类。

当子类和父类均有构造函数时,实例化对象时,子类和父类中的参数均需传入。并通过父类.__init__(self, 参数)的方式将参数传入。其中,self必须显式传入,这是因为它更像是一个普通方法的调用,所有参数必须显式传入,其次,通过类(Human)来调用实例方法(__init__()),必须传入所有参数(参考Student.do_homework()的用法)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 父类
class Human():
sum = 0

def __init__(self, name, age):
self.name = name
self.age = age

def get_name(self):
print(self.name)

# 子类,继承Human类
class Student(Human):
def __init__(self, school):
self.school = school
self.school = school
Human.__init__(self, name, age) # 调用父类构造函数,传入参数

def do_homework(self):
print('do homework')

student1 = Student('人民路小学','student1',18)
print(student1.name) # student1
print(student1.age) # 18

子类方法调用父类方法

子类方法中可以通过 super 关键字来调用父类方法。调用方法如下:

1
super(当前子类,self).父类方法

尽管在上例中,我们可以通过Human.__init__(self, name, age)来调用父类方法,但调用类的实例方法是不推荐使用的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 父类
class Human():
sum = 0

def __init__(self, name, age):
self.name = name
self.age = age

def get_name(self):
print(self.name)

# 子类,继承Human类
class Student(Human):
def __init__(self, school, name, age):
self.school = school
super(Student, self).__init__(name, age) # 使用super实现调用父类构造函数

def do_homework(self):
super(Student, self).do_homework() #可在子类中任意方法中使用super,调用父类方法
print('do homework')

student1 = Student('人民路小学','student1',18)
student1.do_homework()

### output
This is a parent method # 调用的父类方法
do homework # 子类方法

此外,super 关键字不仅可以用在子类的构造函数中,也可以用在子类的任何函数里。

注:当子类存在与父类完全同名的方法时,优先调用子类的方法。

封装性

稍后介绍

多态性

稍后介绍