day24,25组合 封装 多态
面向对象的精髓:将数据和处理数据的代码绑定成一个对象
只要获取到对象相应的数据和方法都有了
一.组合
什么叫组合?
多个对象放在一起叫组合
组合的作用也是降低代码的冗余
# 学生会增加各种各样的新的属性 比如手机 比如电脑, 这样Student中会增加大量的属性和方法
# 后期的维护成本非常高
# 这时就需要使用组合 来完成减少代码冗余
class Phone:
def __init__(self,phonenumber,operator,address):
self.phonenumber=phonenumber
self.operator=operator
self.address=address
def call(self):
print('%s 正在拨号!'% self.phonenumber)
class Person:
def __init__(self,name,sex,age):
self.name=name
self.sex=sex
self.age=age
class Student(Person):
def __init__(self,name,sex,age,number):
super().__init__(name,sex,age)
self.number=number
def show_info(self):
print(self.__dict__)
def select_cursor(self):
print('%s正在选课'% self.name)
class Teacher(Person):
def __init__(self,name,sex,age,salary,level):
super().__init__(name,sex,age)
self.salary=salary
self.level=level
def set_score(self):
print('%s 正在给学生打分'% self.name)
stu1=Student('henry','man','29','3')
p1=Phone('18888888888','中国移动','山西运城')
stu1.phone=p1
stu1.phone.call()
# 通过将手机对象和学生对象进行组合 完成了需求,并且相比较继承而言
# 耦合度低 手机和学生在修改的时候 互不影响
# 同时也减少了代码冗余
# 组合是 对象之间的关系 学生对象拥有手机对象
小练习:
"""
用代码 描述乐队
一个乐队有乐队名,主唱以及其他乐器组成
乐队可以演奏歌曲
主唱是歌手类 会唱歌 ,有名字
钢琴类 能弹奏,有价格,牌子
"""
class Band:
def __init__(self,name,singer,piano):
self.name = name
self.singer = singer
self.piano = piano
def play_music(self):
print("hello 我们%s 组合! 请欣赏" % self.name)
self.singer.singing()
self.piano.playing()
class Singer:
def __init__(self,name):
self.name = name
def singing(self):
print("你好我是歌手 ",self.name)
class Piano:
def __init__(self,price,brand):
self.price = price
self.brand = brand
def playing(self):
print("正在弹琴.....")
# 发现一个歌手
singer = Singer("刘宪华")
# 买一台钢琴
p = Piano("100000000","雅马哈")
# 组件乐队
b = Band("F4",singer,p)
# 开演唱会
b.play_music()
二、面向对象的三大特征之封装
1.什么是封装?
在程序中封装指的是将内容隐藏起来,在面向对象中就是将属性和方法隐藏起来
注意:封装不是单纯的隐藏
封装是指:隐藏内部实现细节,对外提供使用接口
2.为什么封装?
①提高安全性 对封装而言是通过给访问和修改增加额外的逻辑判断来实现的
②封装是为了明确区分内部和外部
3.如何使用封装?
在属性或方法名称前加两个下滑线,就可以为将其设置为私有的
python中权限只有两种,公开的和私有的
属性的封装 需要提供相应 的设置器和访问器
4.封装的特点?
被隐藏的内容 在内部可以直接访问,外部无法访问
总结:对于被隐藏的属性 访问和修改需要通过方法 get用于获取 set用于设置(也称之为设置器和访问器)
5.封装方法的好处
①提高安全性
②隔离复杂度 (将复杂的内容隔离到内部 外部只留下简单的接口 对于使用者难度降低)
class ATM:
def __insert_card(self):
print('请插入银行卡...')
def __input_pwd(self):
print('请输入密码...')
def __select_money(self):
print('请输入取款金额...')
def withdraw(self):
self.__insert_card()
self.__input_pwd()
self.__select_money()
print('取款成功!')
atm=ATM()
atm.withdraw()
print(ATM.__dict__)
6.封装的实现原理
class Person:
def __init__(self,name,sex,age,id_card):
self.name=name
self.sex=sex
self.age=age
self.__id_card=id_card
def get_id_card(self,pwd):
if pwd == '123':
return self.__id_card
else:
print('你无法查看我的身份证信息!')
def set_id_card(self,pwd,new_id_card):
if pwd == '123':
self.__id_card=new_id_card
else:
print('你没有资格修改我的身份证号!')
p1=Person('henry','man',24,'123487349830495584')
print(p1.__dict__)
#结果:{'name': 'henry', 'sex': 'man', 'age': 24, \
'_Person__id_card': '123487349830495584'}
print(p1.get_id_card('123'))
p1.set_id_card('123','142346199810183456')
print(p1.get_id_card('123'))
通过__dict__可以发现
#1.私有属性和方法名称 前自动加上了_类名 python就是通过这种装换的方式来实现封装的
#2.只有在类的内部的双下滑线才能被自动转换,并且这个转换的过程只能执行一次,在类定义完成后后续添加的双下划綫开头的名称是不会自动转换的
p1.__id_card='xxxxx'
print(p1.__id_card) #结果:xxxxx
print(p1.get_id_card('123')) #结果:123487349830495584
#3.父类中私有的方法,子类中无法使用
class A:
def __f1(self):
print("A __f1")
class B(A):
def __f2(self):
self.__f1()
print("B __f2")
def test(self):
self.__f2()
b = B()
b.test()
#结果:报错:'B' object has no attribute '_B__f1'
#在父类中定义的私有方法,子类中无法覆盖
class A:
def f(self):
self.__f1()
def __f1(self):
print('A __f1')
class B(A):
def __f1(self):
print('B __f1')
def f2(self):
self.f()
b=B()
b.f2()
#结果:A __f1
之所以无法覆盖是因为子类和父类中的私有方法名称必然不相同 子类的方法一定是子类独有的 所以无法覆盖
7.property装饰器
BMI案例:
class Person:
def __init__(self,name,weight,height):
self.name=name
self.weight=weight
self.height=height
def bmi(self):
return self.weight/(self.height*self.height)
p1=Person('henry',69,1.76)
print(p1.bmi())
p1.weight+=2
print(p1.bmi())
当一些属性的值 不是固定的而是通过计算得来的时候 我们必须为这个属性增加方法才能完成计算
但是一旦使用方法后 该属性的访问就变成了方法的调用 很明显与其他的属性访问方式不同,这样给使用者造成迷惑
所以需要将这个方法伪装成普通属性 这就用到了property装饰器
我们可以对上述BMI代码进行装饰,将使用方法调用伪装成属性的访问
class Person:
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)
p1=Person('henry',69,1.76)
print(p1.bmi)
p1.weight+=2
print(p1.bmi)
property可以将方法伪装成属性 利用这个特点 我们也可以将其使用到封装中
这时候就可以使用property来进行伪装 使得访问私有属性与访问普通属性的方式一致
property还提供了 setter(用于修改属性的值) 和 deleter(删除属性的值)
class Person:
def __init__(self,name,sex,age,id_card):
self.name=name
self.sex=sex
self.age=age
self.__id_card=id_card
@property
def id_card(self):
return self.__id_card
@id_card.setter
def id_card(self,new_id_card):
self.__id_card=new_id_card
@id_card.deleter
def id_card(self):
del self.__id_card
print('身份证已删除!')
p1=Person('henry','man',24,'123487349830495584')
print(p1.id_card) #结果:123487349830495584
p1.id_card='aaaaaaa'
print(p1.id_card) #结果:aaaaaaa
del p1.id_card
print(p1.__dict__) #结果:{'name': 'henry', 'sex': 'man', 'age': 24}
三、面向对象三大特征之多态
1.什么是多态?
一种事物具备多种形态或者状态 称之为多态
官方解释:不同对象,可以相对应同一方法,并做出不同的行为,产生不同的结果
2.如何实现多态?
让几个不同类拥有相同的父类,这样一来他们就具备了相同的方法,每个子类要覆盖父类的方法,从而每个类的对象行为都不同.
class Phone:
def call(self):
print("手机就能打电话..")
def send_msg(self):
print("手机能发短信..")
class WindowsPhone(Phone):
def call(self):
print("拨号打电话..")
def send_msg(self):
print("输入号码发短信..")
class IPhone(Phone):
def call(self):
print("拨号打电话..")
def send_msg(self):
print("输入号码发短信..")
#可以定义一个方法接受一个手机为参数 无论是是类型的手机 都可以被使用
def CALL(phone):
phone.call()
wp = WindowsPhone()
ipx = IPhone()
CALL(wp)
CALL(ipx)
当使用了多态之后 对象的使用者不需要关系这个对象具体的实现,只需要知道该对象属于哪个基类,就能直接使用它
如此扩展性变高了
3.多态之abc模块
多态是多个类的对象拥有相同的方法,但是我们没有从严格要求说必须提供这些方法,子类完全可以不提供这些方法
# 现在要做的就是 严格要求 子类必须实现父类声明的方法
import abc
# abstract class 是抽象类的缩写 抽象的意思是 不清晰 不具体 看不懂
#使用ABC模块来限制子类 的步骤
#1.为类中指定源类为abc.ABCMeta
#2.在相应的方法上加上abc.abstractmethod装饰器
import abc
# 电脑基类
class Computer(metaclass=abc.ABCMeta):
@abc.abstractmethod
def open(self):
pass
@abc.abstractmethod
def shutdown(self):
pass
class DesktopComputer(Computer):
def open(self):
print("台式机正在启动....")
def shutdown(self):
print("台式机正在关机....")
class Worker:
def working(self,pc):
# 先开机
pc.open()
print("工作中.....")
pc.shutdown()
w1 = Worker()
dp = DesktopComputer()
w1.working(dp)
# 增加了笔记本电脑
class BookComputer(Computer):
def open(self):
print("笔记本正在启动....")
def shutdown(self):
print("笔记本正在关机....")
bc = BookComputer()
w1.working(bc)
class PadComputer(Computer):
def open(self):
print("平板正在启动....")
def shutdown(self):
print("平板正在关机....")
bc = PadComputer()
w1.working(bc)
4.鸭子类型
python推崇简单的编程方式
鸭子类型 如果一个对象叫声像鸭子 走路也想鸭子 那就把它当成鸭子
对应到代码中就是: 只要你的行为一样 那就把你当成同一个类型来看待
class Duck:
def bark(self):
print("鸭子嘎嘎叫...")
def run(self):
print("摇摇晃晃走....")
class Chicken:
def bark(self):
print("鸡咯咯叫...")
def run(self):
print("摇摇晃晃走....")
def test(obj):
obj.bark()
obj.run()
duck = Duck()
c = Chicken()
test(duck)
test(c)
如果你足够自觉 你可以不使用abc模块 也不需要基类 自觉地将方法名字都写成一样 同样可以实现多态
这种方式称之为鸭子类型
day24,25组合 封装 多态的更多相关文章
- 面向对象之 组合 封装 多态 property 装饰器
1.组合 什么是组合? 一个对象的属性是来自另一个类的对象,称之为组合 为什么要用组合 组合也是用来解决类与类代码冗余的问题 3.如何用组合 # obj1.xxx=obj2''''''# class ...
- Python学习day25-面向对象之组合,多态和封装
figure:last-child { margin-bottom: 0.5rem; } #write ol, #write ul { position: relative; } img { max- ...
- 面向对象(三)——组合、多态、封装、property装饰器
组合.多态.封装.property装饰器 一.组合 1.什么是组合 组合指的是某一个对象拥有一个属性,该属性的值是另外一个类的对象 class Foo(): pass class Bar(): pas ...
- python之面向对象性封装,多态,以及鸭子类型
默认类型 class A: class_name = 'python23期' def __init__(self, name, age): self.name = name self.age =age ...
- OOP面向对象 三大特征 继承封装多态
OOP面向对象 ----三大特征 继承封装多态 面向对象(Object Oriented,OO)是软件开发方法.面向对象的概念和应用已超越了程序设计和软件开发,扩展到如数据库系统.交互式界面.应用结构 ...
- Python进阶(十六)----面向对象之~封装,多态,鸭子模型,super原理(单继承原理,多继承原理)
Python进阶(十六)----面向对象之~封装,多态,鸭子模型,super原理(单继承原理,多继承原理) 一丶封装 , 多态 封装: 将一些东西封装到一个地方,你还可以取出来( ...
- java 封装多态继承
java 面向对象思想 封装多态继承 面向过程与面向对象 编程分为面向对象编程和面向对象编程,汇编,C语言是面向过程写代码,C++/Java是面向对象 其实面向过程和面向对象在本质都是一样写代码,然后 ...
- 组合,多态与多态性,封装以及property装饰器介绍
一:组合: 什么是组合:组合指的是某一个对象拥有一个属性,该属性的值是另外一个类的对象. 为何要用组合:通过为某一个对象添加属性(属性的值是另外一个类的对象)的方式,可以间接地将两个类关联/整合/组合 ...
- 组合+封装+property+多态+鸭子类型(day21)
目录 昨日回顾 继承 什么是继承 继承的目的 什么是抽象 继承背景下,对象属性的查找顺序 派生 什么是派生 子类派生出新的属性,重用父类的属性 新式类和经典类 钻石继承的继承顺序 今日内容 一.组合 ...
随机推荐
- Solaris 10主机名和IP地址步骤
1.修改主机名: hostname newname vi /etc/hosts vi /etc/hostname.e1000g0 vi /etc/nodename init 6 #重启 --confi ...
- sqli-labs(十二)(and和or的过滤)
第二十五关: 这关是过滤了and 和or 输入?id=1' or '1'='1 发现or被过滤了,将or换成and也一样. 输入?id=1' oorr '1'='1 这样就可以了,将一个or置空后,o ...
- LINK : fatal error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏。
问题描述:VS2010 LINK : fatal error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏. 解决办法: 修改嵌入清单选项为否,然后重新便于创建. 参考自:htt ...
- EF或LINQ 查询时使用IN并且根据列表自定义排序方法
EF和LINQ改变了原有的手写SQL时期的一些编码方法,并且增强了各数据库之间的移植性简化了开发时的代码量和难度,由于很多人不熟,经常会碰到一些写SQL语句时经常会用到的一些方法,而使用EF或LINQ ...
- Beta冲刺1.0
1. 提供当天站立式会议照片一张 2. 每个人的工作 (有work item 的ID) 3. 发布项目燃尽图 4. 每人的代码/文档签入记录 (1)代码签入记录 (2)代码签入链接 链接1 链 ...
- sitecore系统教程之架构概述
Sitecore体验数据库(xDB)从实时大数据存储库中的所有通道源收集所有客户交互.它连接交互数据,为每个客户创建全面,统一的视图,并使营销人员可以使用数据来管理客户的实时体验. xDB架构非常灵活 ...
- VM VirtualBox 全屏模式 && 自动缩放模式 相互切换
[1]自动缩放模式 热键Host + C 偶然一次机会,把虚拟机切换为了自动缩放模式,如下图: 想要再切换为全屏模式,发现不知如何操作,后来折腾了一会儿,切换成功.以此备录一下. [2]切换为全屏模式 ...
- python3安装scrapy教程
2.1xm1http://www.lfd.uci.edu/~gohlke/pythonlibs/#lxml3. PyOpensslhttps://pypi.python.org/pypi/pyOpen ...
- Linux基础命令---ping
ping ping指令可以发送ICMP请求到目标地址,如果网络功能正常,目标主机会给出回应信息.ping使用ICMP协议强制发送ECHO_REQUEST报文到目标主机,从主机或网关获取ICMP ECH ...
- scala语言中的case关键字在spark中的一个奇特使用
package com.spark.demo import com.spark.demo.util.SparkUtil import org.apache.spark.rdd.RDD import s ...