面向对象-组合
1.什么是组合
组合指的是某一个对象拥有一个属性,该属性的值是另外一个类的对象
1 class Foo:
2 xxx = 111
3
4 class Bar:
5 yyy = 222
6
7 obj = Foo()
8 obj.attr = Bar()
9
10 print(obj.xxx)
11 >>>111
12 print(obj.attr.yyy)
13 >>>222
2.为何要用组合
通过为某一个对象添加属性(属性的值是另外一个类的对象)的方式,可以间接地将两个类关联/整合/组合到一起
从而减少类与类之间代码冗余
1 class Foo1:
2 pass
3 class Foo2:
4 pass
5 class Foo3:
6 pass
7
8 class Bar:
9 pass
10
11 obj_from_bar=Bar()
12
13 obj1=Foo1()
14 obj2=Foo2()
15 obj3=Foo3()
16
17 obj1.attr1=obj_from_bar
18 obj2.attr2=obj_from_bar
19 obj3.attr3=obj_from_bar
3.如何用组合
1 class OldboyPeople:
2 school = 'Oldboy'
3
4 def __init__(self, name, age, sex, ):
5 self.name = name
6 self.age = age
7 self.sex = sex
8
9
10 class OldboyStudent(OldboyPeople):
11 def __init__(self, name, age, sex, score=0):
12 OldboyPeople.__init__(self, name, age, sex)
13 self.score = score
14 self.courses = []
15
16 def choose_course(self):
17 print('%s choosing course' % self.name)
18
19 def tell_all_course(self):
20 print(('学生[%s]选修的课程如下' % self.name).center(50, '='))
21 for obj in self.courses:
22 obj.tell_info()
23 print('=' * 60)
24
25
26 class OldboyTeacher(OldboyPeople):
27 def __init__(self, name, age, sex, level):
28 OldboyPeople.__init__(self, name, age, sex)
29 self.level = level
30 self.courses = []
31
32 def score(self, stu, num):
33 stu.score = num
34
35 def tell_all_course(self):
36 print(('老师[%s]教授的课程如下' % self.name).center(50, '*'))
37 for obj in self.courses:
38 obj.tell_info()
39 print('*' * 70)
40
41
42 class Course:
43 def __init__(self, c_name, c_price, c_period):
44 self.c_name = c_name
45 self.c_price = c_price
46 self.c_period = c_period
47
48 def tell_info(self):
49 print('<课程名:%s 价钱:%s 周期:%s>' % (self.c_name, self.c_price, self.c_period))
50
51
52 # 创建课程对象
53 python = Course('python全栈开发', 1900, '5mons')
54 linux = Course('linux架构师', 900, '3mons')
55
56 stu1 = OldboyStudent('刘二蛋', 38, 'male')
57 stu1.courses.append(python)
58 stu1.courses.append(linux)
59 stu1.tell_all_course()
60
61 tea1 = OldboyTeacher('egon', 18, 'male', 10)
62 tea1.courses.append(python)
63 tea1.tell_all_course()
面向对象-多态与多态性
1.什么是多态
多态指的是同一种/类事物的不同形态
2.为何要用多态
多态性:在多态的背景下,可以在不用考虑对象具体类型的前提下而直接使用对象
3.如何用多态
Animal() #父类只是用来建立规范的,不能用来实例化,更无需实现内部的方法
1 import abc
2
3
4 class Animal(metaclass=abc.ABCMeta):
5 @abc.abstractmethod
6 def speak(self):
7 pass
8
9 @abc.abstractmethod
10 def run(self):
11 pass
12
13
14
15 class People(Animal):
16 def speak(self):
17 print('say hello')
18
19 def run(self):
20 pass
21
22
23 class Dog(Animal):
24 def speak(self):
25 print('汪汪汪')
26
27 def run(self):
28 pass
29
30
31 class Pig(Animal):
32 def speak(self):
33 print('哼哼哼')
34
35 def run(self):
36 pass
37
38
39 obj1 = People()
40 obj2 = Dog()
41 obj3 = Pig()
Python推崇的是鸭子类型,只要你叫的声音像鸭子,并且你走路的样子也像鸭子,那你就是鸭子
1 class Disk:
2 def read(self):
3 print('Disk read')
4
5 def write(self):
6 print('Disk write')
7
8
9 class Memory:
10 def read(self):
11 print('Mem read')
12
13 def write(self):
14 print('Mem write')
15
16
17 class Cpu:
18 def read(self):
19 print('Cpu read')
20
21 def write(self):
22 print('Cpu write')
23
24
25 obj1 = Disk()
26 obj2 = Memory()
27 obj3 = Cpu()
28
29 obj1.read()
30 obj2.read()
31 obj3.read()
面向对象-封装
1.什么是封装
装: 往容器/名称空间里存入名字
封: 代表将存放于名称空间中的名字给藏起来,这种隐藏对外不对内
2.为何要封装
封装数据属性:
将数据属性隐藏起来,类外就无法直接操作属性,需要类内部开辟一个接口,让外部的使用可以间接地操作属性,可以在接口内定制任意的控制逻辑,从而严格控制使用者对属性的操作
1 class People:
2 def __init__(self, name, age):
3 self.__name = name
4 self.__age = age
5
6 def tell_info(self):
7 print('<name:%s age:%s>' % (self.__name, self.__age))
8
9 def set_info(self, name, age):
10 if type(name) is not str:
11 print('名字必须是str类型傻叉')
12 return
13 if type(age) is not int:
14 print('年龄必须是int类型傻叉')
15 return
16 self.__name = name
17 self.__age = age
18
19
20 obj = People('egon', 18)
21 obj.set_info('EGON', '18')
22 obj.tell_info()
封装函数属性: 隔离复杂度
1 class ATM:
2 def __card(self):
3 print('插卡')
4
5 def __auth(self):
6 print('用户认证')
7
8 def __input(self):
9 print('输入取款金额')
10
11 def __print_bill(self):
12 print('打印账单')
13
14 def __take_money(self):
15 print('取款')
16
17 def withdraw(self):
18 self.__card()
19 self.__auth()
20 self.__input()
21 self.__print_bill()
22 self.__take_money()
23
24
25 a = ATM()
26 a.withdraw()
3.如何封装
在类内定义的属性前加__开头(没有__结尾)
总结:
1. __开头的属性实现的隐藏仅仅只是一种语法意义上的变形,并不会真的限制类外部的访问
2. 该变形操作只在类定义阶段检测语法时发生一次,类定义阶段之后新增的__开头的属性并不会变形
3. 如果父类不想让子类覆盖自己的属性,可以在属性前加__开头
1 class Foo:
2 def __f1(self): # _Foo__f1
3 print('Foo.f1')
4
5 def f2(self):
6 print('Foo.f2')
7 self.__f1() # obj._Foo__f1()
8
9
10 class Bar(Foo):
11 def __f1(self): # _Bar__f1
12 print('Bar.f1')
13
14
15 obj = Bar()
16
17 >>>Foo.f2
18 >>>Foo.f1
面向对象-property
property装饰器是用来将类内的函数属性伪装成数据属性
1 class People:
2 def __init__(self, name):
3 self.__name = name
4
5 @property
6 def name(self):
7 return '<名字:%s>' % self.__name
8
9 @name.setter
10 def name(self, obj):
11 if type(obj) is not str:
12 print('name必须为str类型')
13 return
14 self.__name = obj
15
16 @name.deleter
17 def name(self):
18 print('不让删')
19
20 obj = People('egon')
21 del obj.name
22 print(obj.__dict__)