Day 21 组合/封装/property特性/多态和多态性/抽象类/鸭子类型
目录
组合
什么是组合
组合就是一个类的对象具备某一个属性,该属性的值是指向另外一个类的对象
为什么要使用组合
为了减少类与类之间代码的冗余
如何使用组合
class Course:
def __init__(self, course_name, course_period):
self.course_name = course_name
self.course_period = course_period
def tell_info(self):
print(f'''
课程信息
课程名称:{self.course_name}
课程时长:{self.course_period}
''')
class Student:
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
self.course_list = []
def choose_course(self, course_obj):
self.course_list.append(course_obj)
def tell_course_info(self):
for course in self.course_list:
course.tell_info()
# 创建课程和学生对象
python = Course('python', '6个月')
stu = Student('Tiny', 18, 'male')
#添加课程
stu.choose_course(python)
# 获取课程信息
stu.tell_course_info()
封装
什么是封装
封装指的是将一堆属性(特征和技能)放到一个对象中
为什么要封装
- 封装数据的原因:保护隐私
- 封装方法的原因:隔离复杂度
两个层面的封装
封装其实分为两个层面,但无论哪种封装,都要对外界提供好访问你内部隐藏内容的接口(接口可以理解为入口,有了这个入口,使用者无需且不能够直接访问到内部隐藏的细节,只能走接口,并且我们可以在接口的实现上附加更多的处理逻辑,从而严格控制使用者的访问)
第一个层面的封装
创建类和对象会分别创建二者的名称空间,我们可以用类名.或者对象.的方式去访问里面的名字,这本身就是一种封装
注意:对于这一层面的封装,类名.和对象名.就是访问隐藏属性的接口
第二个层面的封装
类中把某些属性和方法隐藏起来(或者说定义成私有),只有类的内部使用,外部无法访问,或者留下少量接口(函数)供外部使用
在python中用__(双下划线)的方式来实现隐藏属性(私有化)
类中所有双下划线开头的名称如__x都会自动变成:_类名__x的形式:
class A:
__name = 'Tiny'
def __foo(self):
print('from A')
def get_name(self):
return self.__name
def set_name(self):
self.__name = 'Nick'
a = A()
print(a.get_name())
a.set_name()
print(a.get_name())
print(a._A__name)
Tiny
Nick
Nick
这种自动变形的特点:
- 类中定义的__name只能在类中使用,如self.__name
- 这种变形其实正是针对内部的变形,在外部是无法通过__name这个名字访问到的
- 在子类定义的__name不会覆盖在父类定义的__name,因为子类中变形成了_子类名__name,而父类中变形成了_父类名__name,即双下划线开头的属性在继承给子类时,子类是无法覆盖的
注意:对于这一层面的封装,我们需要在类中定义一个函数(接口函数)在它内部访问被隐藏的属性,然后外部就可以使用了
这种变形需要注意的问题是:
- 这种机制也并没有真正意义上限制我们从外部直接访问,知道了类名和属性名就可以拼出名字,_类名__属性名,然后就可以访问了
- 变形的过程只在类的定义时发生一次,在定义后的赋值操作,不会变形
- 在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的
类的property特性
什么是property特性
property装饰器用于将被装饰的方法伪装成一个数据属性,在使用时可以不加括号而直接使用
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
people = People('tiny', 54, 1.7)
print(people.bmi)
people.set_name = 'jack'
print(people.get_name)
property属性的定义和调用要注意以下几点:
- 定义是,在实例方法的基础上添加@property装饰器;并且仅有一个self参数
- 调用时,无需括号
类的多态和多态性
什么是多态
多态指的是一类事物有多种形态
- 序列数据类型有多种形态:字符串,列表,元组
- 动物有多种形态:人,狗,猪
什么是多态性
多态性是指具有不同功能的函数可以使用相同的函数名,这样就可以用一个函数名调用不同内容的函数.
class Pig:
def run(self):
print('pig is running')
class Dog:
def run(self):
print('dog is running')
pig = Pig()
dog = Dog()
pig.run()
dog.run()
抽象类
什么是抽象类
abc模块 abstract_class
为什么使用抽象类
强制子类必须遵循父类的一套标准
如何使用抽象类
import abc
class Animal(metaclass=abc.ABCMeta):
@abc.abstractmethod
def run(self):
pass
class Pig(Animal):
def run(self):
print('pig is running')
class Dog(Animal):
def run(self):
print('dog is running')
pig = Pig()
dog = Dog()
pig.run()
dog.run()
鸭子类型
什么是鸭子类型
Duck typing 这个概念来源于美国印第安纳州的诗人詹姆斯·惠特科姆·莱利(James Whitcomb Riley,1849-
1916)的诗句:”When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck.”
在python中,不推荐使用抽象类来强制限制子类的定义,但是推荐都遵循鸭子类型
继承:
耦合性太高,程序的可扩展性差
鸭子类型:
耦合性低,程序的可扩展性强
原文地址:https://www.cnblogs.com/2222bai/p/11655187.html
- Android 数据绑定框架DataBinding,堪称解决界面逻辑的黑科技
- 汽车黑客:没有Security就没有Safety
- Android 自定义View高级特效,神奇的贝塞尔曲线
- Android二维码扫描开发(一):实现思路与原理
- 说一道简单的BCTF题 – 分分钟而已
- 安全扫描工具Nmap引擎理解文档
- AppFuse项目笔记(1)
- 电子商务系统ShopNC多个漏洞(可暴力 getshell)
- 利用Google爬虫DDoS任意网站
- 极客都应该知道的Linux技巧
- 酷似感冒,变色龙病毒可在WiFi接入点间感染
- Linux下的常见错误配置
- 使用C#实现蜘蛛程序
- Android热修复实践应用—AndFix
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法