面向对象进阶

为了能够更好的使用面向对象编程思想进行程序开发,我们需要对Python中的面向对象编程进行更为深入的了解。

@property装饰器

目的:通过getter(访问器)和setter(修改器)对私有属性进行操作,使得对属性的访问既安全又方便。

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
28
29
30
31
32
33
34
35
class Person(object):

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

#访问器 -getter方法
@property
def name(self):
return self._name
@property
def age(self):
return self._age

#修改器 - setter方法
@age.setter
def age(self,age):
self._age = age

def play(self):
if self.age <= 16 :
print('%s正在玩弹珠。'% self._name)
else:
print('%s正在玩狼人杀。'% self._name)


def main():
person = Person("YYQ",12)
person.play()
person.age = 22
person.play()


if __name__ == '__main__':
main()

运行结果为:

1
2
YYQ正在玩弹珠。
YYQ正在玩狼人杀。

__slots__魔法

如果我们需要限定自定义类型的对象只能绑定某些属性,可以通过在类中定义__slots__变量来进行限定。需要注意的是__slots__的限定只对当前类的对象生效,对子类并不起任何作用。

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
28
29
30
31
32
33
34
35
class Person(object):

# 限定Person对象只能绑定_name, _age和_gender属性
__slots__ = ('_name', '_age', '_gender')

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

@property
def name(self):
return self._name

@property
def age(self):
return self._age

@age.setter
def age(self, age):
self._age = age

def play(self):
if self._age <= 16:
print('%s正在玩弹珠。' % self._name)
else:
print('%s正在玩狼人杀。' % self._name)


def main():
person = Person('YYQ', 23)
person.play()
person._gender = '男'

if __name__ == '__main__':
main()

运行结果为:

1
YYQ正在玩狼人杀。

静态方法和类方法

静态方法

之前写在类中的方法都是针对对象的,实际上,在累的方法并不需要都是对象方法,例如我们根据三角形三条边计算周长面积,由于事先并不知道能不能构成三角形,所以我们在类里面写一个方法判断是否能构成三角形,这个方法显然不是对象方法,因为在调用这个方法的时候三角形对象还没有创建出来,这里采用静态方法来解决这类问题,来看看代码吧:

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
28
29
30
31
from math import sqrt

class Triangle(object):

def __init__(self,a,b,c):
self._a = a
self._b = b
self._c = c

@staticmethod
def is_valid(a,b,c):
return a + b > c and b + c > a and a + c > b

def perimeter(self):
return self._a + self._b + self._c

def area(self):
half = self.perimeter() / 2
return sqrt(half * (half - self._a) * (half - self._b) * (half - self._c))

def main():
a,b,c = 3,4,5
if Triangle.is_valid(a,b,c):
t = Triangle(a,b,c)
print(t.perimeter())
print(t.area())
else:
print('无法构成三角形')

if __name__ == '__main__':
main()

运行结果为:

1
2
12
6.0

类方法

和静态方法比较类似,Python还可以在类中定义类方法,类方法的第一个参数约定名为cls,它代表的是当前类相关的信息的对象(类本身也是一个对象,有的地方也称之为类的元数据对象),通过这个参数我们可以获取和类相关的信息并且可以创建出类的对象,代码如下所示。

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
from time import time, localtime, sleep


class Clock(object):
"""数字时钟"""

def __init__(self, hour=0, minute=0, second=0):
self._hour = hour
self._minute = minute
self._second = second

@classmethod
def now(cls):
ctime = localtime(time())
return cls(ctime.tm_hour, ctime.tm_min, ctime.tm_sec)

def run(self):
"""走字"""
self._second += 1
if self._second == 60:
self._second = 0
self._minute += 1
if self._minute == 60:
self._minute = 0
self._hour += 1
if self._hour == 24:
self._hour = 0

def show(self):
"""显示时间"""
return '%02d:%02d:%02d' % (self._hour, self._minute, self._second)


def main():
# 通过类方法创建对象并获取系统时间
clock = Clock.now()
while True:
print(clock.show())
sleep(1)
clock.run()


if __name__ == '__main__':
main()

继承和多态

继承

继承是指让一个类从另一个类那里将属性和方法直接继承下来,从而减少重复代码的编写

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
class Person(object):
"""人"""

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

@property
def name(self):
return self._name

@property
def age(self):
return self._age

@age.setter
def age(self, age):
self._age = age

def play(self):
print('%s正在愉快的玩耍.' % self._name)

def watch_av(self):
if self._age >= 18:
print('%s正在观看动物世界.' % self._name)
else:
print('%s只能观看《熊出没》.' % self._name)


class Student(Person):
"""学生"""

def __init__(self, name, age, grade):
super().__init__(name, age)
self._grade = grade

@property
def grade(self):
return self._grade

@grade.setter
def grade(self, grade):
self._grade = grade

def study(self, course):
print('%s的%s正在学习%s.' % (self._grade, self._name, course))


class Teacher(Person):
"""老师"""

def __init__(self, name, age, title):
super().__init__(name, age)
self._title = title

@property
def title(self):
return self._title

@title.setter
def title(self, title):
self._title = title

def teach(self, course):
print('%s%s正在讲%s.' % (self._name, self._title, course))


def main():
stu = Student('YYQ', 15, '初三')
stu.study('数学')
stu.watch_av()
t = Teacher('AA', 38, '老叫兽')
t.teach('Python程序设计')
t.watch_av()


if __name__ == '__main__':
main()

多态

子类在继承了父类的方法后,可以对父类已有的方法给出新的实现版本,这个动作称之为方法重写(override)。通过方法重写我们可以让父类的同一个行为在子类中拥有不同的实现版本,当我们调用这个经过子类重写的方法时,不同的子类对象会表现出不同的行为,这个就是多态(poly-morphism)。

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
28
29
30
31
32
33
34
35
36
37
from abc import ABCMeta, abstractmethod


class Pet(object, metaclass=ABCMeta):
"""宠物"""

def __init__(self, nickname):
self._nickname = nickname

@abstractmethod
def make_voice(self):
"""发出声音"""
pass


class Dog(Pet):
"""狗"""

def make_voice(self):
print('%s: 汪汪汪...' % self._nickname)


class Cat(Pet):
"""猫"""

def make_voice(self):
print('%s: 喵...喵...' % self._nickname)


def main():
pets = [Dog('旺财'), Cat('凯蒂'), Dog('大黄')]
for pet in pets:
pet.make_voice()


if __name__ == '__main__':
main()

在上面的代码中,我们将Pet类处理成了一个抽象类,所谓抽象类就是不能够创建对象的类,这种类的存在就是专门为了让其他类去继承它。Python从语法层面并没有像Java或C#那样提供对抽象类的支持,但是我们可以通过abc模块的ABCMeta元类和abstractmethod包装器来达到抽象类的效果,如果一个类中存在抽象方法那么这个类就不能够实例化(创建对象)。上面的代码中,DogCat两个子类分别对Pet类中的make_voice抽象方法进行了重写并给出了不同的实现版本,当我们在main函数中调用该方法时,这个方法就表现出了多态行为(同样的方法做了不同的事情)。

0%