面向对象的组合、封装、多态
组合:
组合指的是一个对象中的属性,是另一个对象.
目的:减少代码的冗余
例子:
1.学生类,老师类, 学生和老师都有课程属性, 每一门课程都是一个对象.
课程: 课程名字,课程周期,课程价钱
2.学生和老师都有选择课程的功能, 还有打印所有课程的功能.
class People: def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex # 添加一门课程方法 def add_course(self, course_obj): self.course_list.append(course_obj) # 打印当前对象中所有课程的课程信息 def tell_all_course(self): # 拿到当前对象的课程列表,列表中存放的是一个个的课程对象 for course_obj in self.course_list: # 每一个课程对象调用查看课程信息的方法 course_obj.tell_course_info() class Teacher(People): def __init__(self, name, age, sex): super().__init__(name, age, sex) # 用来存放课程对象 self.course_list = [] class Student(People): def __init__(self, name, age, sex): super().__init__(name, age, sex) self.course_list = [] # 课程类 class Course: def __init__(self, course_name, course_period, course_price): # 课程名称\周期\价格 self.course_name = course_name self.course_period = course_period self.course_price = course_price def tell_course_info(self): print(f''' 课程名称: {self.course_name} 课程周期: {self.course_period} 课程价钱: {self.course_price} ''') tea1 = Teacher('tank', 17, 'male') stu1 = Student('张全蛋', 20, 'female') python_obj = Course('python', 6, 2.0) linux_obj = Course('linux', 6, 1.0) # 添加python与linux课程 tea1.add_course(python_obj) tea1.add_course(linux_obj) # tea1.course_list[0].tell_course_info() tea1.tell_all_course()
封装
封装指的是把一堆属性(特征与技能)封装到一个对象中.
存数据的目的是为了取, 对象可以"."的方式获取属性.
比喻: 对象就好比一个袋子, 袋子里面装一堆属性.
封装的目的为了方便存取,可以通过对象.属性的方式获取属性.
如何封装
特征: 变量 ---> 数据属性
技能: 函数 ---> 方法属性
在类内部,定义一堆属性(特征与技能).
通过 对象.属性 = 属性值
比如:__name = 'tank' 此时直接打印__name 会报错,没有__name的属性
2.访问限制机制的目的?
一堆隐私的属性与不能被外部轻易访问的属性, 可以隐藏起来,不被外部直接调用.
好处:
对重要数据获取的逻辑更加严谨, 进而保证了数据的安全.
接口: 隐私属性可以通过封装一个接口,在接口内做业务逻辑的处理,再把数据返回给调用者.
注意: 在python中,不会强制限制属性的访问,类内部__开头的属性,只是做了一种变形.
若想直接访问, 调用变形后的名字即可.
class Foo:
__name = 'tank' # ---> _类名__属性名
class Foo: # 数据属性 __name = 'tank' # 方法属性 def __run(self): print('running..') # 接口: 获取数据接口 def get_name(self): return self.__name def set_name(self): self.__name = 'jason_sb' foo = Foo() print(foo.__name) #报错没有__name res = foo.get_name() print(res) #接口调用得到__name print(foo._Foo__name) # --> _Foo__name #或者直接用 _类名__属性名调用 foo.set_name()# 通过接口修改被隐藏的属性值 print(foo.get_name())
class Teacher: def __init__(self, name, age, sex): self.__name = name self.__age = age self.__sex = sex # 接口: 打印用户信息接口 def get_info(self): # 用户认证 user = input('user: ').strip() pwd = input('pwd: ').strip() if user == 'tank' and pwd == '123': #通过密码认证,然后接口再调用打印隐藏属性 print(f''' 姓名: {self.__name} 年龄: {self.__age} 性别: {self.__sex} ''') # 接口: 修改用户信息接口 def set_info(self, name, age, sex): # str1 = 'string' # str('string') if not isinstance(name, str): raise TypeError('名字必须要使用字符串') if not isinstance(age, int): raise TypeError('年龄必须是数字') if not isinstance(sex, str): raise TypeError('性别必须要使用字符串') self.__name = name self.__age = age self.__sex = sex tea1 = Teacher('tank', 17, 'male') # tea1.get_info() tea1.set_info('jason_sb', 101, 'female') tea1.get_info()
class ATM: # 1.插卡 def __insert_card(self): print('插卡') pass # 2.输入密码 def __input_pwd(self): print('密码验证') pass # 3.输入取款金额 def __input_money(self): print('输入金额') pass # 4.开始吐钱 def __get_money(self): print('执行吐钱') pass # 5.打印账单 def __print_flow(self): print('打印账单') pass # 取钱直接接口 规定程序执行的顺序 def withdraw(self): self.__insert_card() self.__input_pwd() self.__input_money() self.__get_money() self.__print_flow() print('取款程序执行完毕!') atm = ATM() atm.withdraw()
property
1. 什么是property
python内置的装饰器, 主要是给类内部的方法使用.
2. 为什么要用property
在对象调用某个方法时,将对象.方法()变成对象.方法(看起来想一个普通的数据属性)
obj.bmi() == obj.bmi
- 如何使用property
@property
def 类内部的方法(self):
如 @property
def get_name(self):
如果此时想要修改改方法的返回值,不能直接修改
# 改
@get_name.setter #get_name要与想修改返回值的方法名一致.setter是固定的单词
def set_name(self, val):
self.name = val
# 删除
@get_name.deleter
def del_name(self):
del self.name
class People: def __init__(self, name, weight, height): self.name = name self.weight = weight self.height = height @property def bmi(self): return self.weight / (self.height * self.height) # 了解 @property def get_name(self): return self.name # 改 @get_name.setter def set_name(self, val): self.name = val # 删除 @get_name.deleter def del_name(self): del self.name p = People('jason', 200, 1.6) # print(p.bmi()) # 打印动词,看起来不合理 print(p.bmi) # ---> p.bmi() # 注意: 不能对被装饰过的方法属性修改. # p.bmi = 18 # # 了解: 若真要通过此方法修改属性,可以通过另一种方式修改. # print(p.get_name) # p.set_name = 'tank' # print(p.get_name) # # p.del_name() # # print(p.get_name)
多态
多态的目的:
多态也称之为多态性, 在程序中继承就是多态的表现形式.
多态的目的是为了, 让多种不同类型的对象, 在使用相同功能的情况下,调用同一个名字的方法名.
父类: 定义一套统一的标准.
子类: 遵循父类统一的标准.
多态的最终目的: 统一子类编写的规范, 为了让使用者更方便调用相同功能的方法.
3.如何实现:
- 继承
注意: 在python中,不会强制要求子类必须遵循父类的一套标准,所以出现了抽象类.
class Animal: # 吃 def eat(self): pass # 喝 def drink(self): pass # 叫 def speak(self): pass # 猪 class Pig(Animal): # 吃 def eat(self): print('猪在吃饭') pass # 喝 def drink(self): pass def speak(self): print('哼哼哼~~~') # 猫 class Cat: # 吃 def eat(self): print('猫在吃饭') pass # 喝 def drink(self): pass def speak(self): print('喵喵喵~~') # 狗 class Dog: # 吃 def eat(self): print('狗在吃饭') pass # 喝 def drink(self): pass def speak(self): print('汪汪汪~~~') # 正确教材 pig = Pig() cat = Cat() dog = Dog() pig.speak() cat.speak() dog.speak()
抽象类
2.使用的目的?
强制子类必须遵循父类的一套标准.
3.如何使用
import abc
class 父类()在括号内写入 metaclass=abc.ABCMeta,然后在父类的方法里面加上@abc.abstractmethod这个装饰器
子类里面必须要有父类里面所有装饰过的方法,不能少,但可以派生自己的反法
import abc class Animal(metaclass=abc.ABCMeta): # 吃 @abc.abstractmethod def eat(self): pass # 喝 @abc.abstractmethod def drink(self): pass # 叫 @abc.abstractmethod def speak(self): pass # 猪 class Pig(Animal): # 吃 def eat(self): print('猪在吃饭') pass # 喝 def drink(self): pass def speak(self): print('哼哼哼~~~') # 派生 def run(self): pass pig = Pig()
鸭子类型
1. 什么是鸭子类型?
在不知道当前对象是何物的情况下,但是你长得像鸭子,那么你就是鸭子类型.
在python中,不推荐使用抽象类强制限制子类的定义,但是推荐 类都遵循鸭子类型.
2. 继承:
耦合性太高,程序的可扩展性差
3. 鸭子类型:
耦合度低,程序的可扩展性强
多态炫技操作
# 猪 class Pig: # 吃 def eat(self): print('猪在吃饭') pass # 喝 def drink(self): pass def speak(self): print('哼哼哼~~~') # 猫 class Cat: # 吃 def eat(self): print('猫在吃饭') pass # 喝 def drink(self): pass def speak(self): print('喵喵喵~~') # 狗 class Dog: # 吃 def eat(self): print('狗在吃饭') pass # 喝 def drink(self): pass def speak(self): print('汪汪汪~~~') dog = Dog() cat = Cat() pig = Pig() def BARK(animal): # 自定义了一个函数 animal.speak() BARK(dog) BARK(cat) BARK(pig)
str1 = '1234' list1 = [1, 2, 3] print(str1.__len__()) print(list1.__len__()) def LEN(d): return d.__len__() print(LEN(str1)) print(LEN(list1)) print(len(str1)) print(len(list1))