面向对象---封装,继承,多态
之前的博客都是在描述将书面向过程,一步步从头到尾的去做这个事情,函数编程的话是提高了代码的可读性,.
可是为什么写代码写函数的时候要将函数放在里面呢?
将相同类的函数放在里面,进行好好的调用,所以这个是模块的划分.
首先我们学习面向对象之前要和之前函数做一个对比:
如果开发一个消息提醒的功能,邮件短信,微信的提醒
你如果用函数写的话,他的格式应该是
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
若是用面向对象的格式写的话他的格式应该是:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class Message: def email(self, em, text): """ 发送邮件 :return: """ print(em,text) def msg(self, tel, text): """ 发送短信 :return: """ print(tel,text) def wechat(self, num, text): """ 发送微信 :return: """ print(num,text) # 编写功能:假设用户购买课程,然后给alex发送提醒; if 1==1: obj = Message() obj.email('alex@sb.com', '张进购买了一个学位课') obj.msg('188888888','张进购买了一个学位课') obj.wechat('xxxx','张进购买了一个学位课')
把函数放在里面,不可以原生放在那里,要在参数里面加入self 这个就编写完成了~是不是觉得很nice?
self自动调用了这个位置的值,但是你需要注意的是面向对象的命名最好的用大写,不然不专业,如果你要用小写是可以,但是看起来的话很low的,
刚才从两个对比你觉得哪个好呢?
函数:定义简单,调用简单
面向对象:定义复杂调用也是很复杂的,好处:将某些类似的功能写在一起,但是缺点大于优点...
所以从刚才两个式子我们可以总结出:
1.函数式编程可能会比面向对象更好一些
2.Python中可以支持两种编写方式
3.面向对象格式:
class + 类名()#定义一个类
def函数名(self)这个你需要些self的,不然不专业,也可以叫其他的:#在类编写了一个方法
pass
调用:
x1 = 类名()#类后面加()意思就是创建了一个对象,也可以说实例化了一个对象
x1函数名()#通过对象掉漆其中的一个方法
以上的话就是类的编写
之前在函数的时候,举例过购物车
那如何用面向对象编写购物车呢?那我简单就那登录举个例子:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class Account: def login(self): user = input('请输入用户名:') pwd = input('请输入密码:') if user == 'alex' and pwd == 'sb': print('登录成功') else: print('登录失败') obj = Account() obj.login()
刚才对比了第一个回合你会觉得面向对象并不是占有优势
所以第二回合开始了
完成以下功能:
赵四/20岁/男/倾国倾城
赵四/20岁/男/闭月羞花
老四/20岁/男/美炸出一个花
如果用函数
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def cy(name,age,gender): date = '%s今年%s,他的相貌%s'%(name,age,gender) print(date) def ly(name,age,gender): date = '%s今年%s,他的相貌%s'%(name,age,gender) print(date) def zh(name,age,gender): date = '%s今年%s,他的相貌%s'%(name,age,gender) print(date) cy('赵四','20','沉鱼落雁') ly('赵四','20','闭月羞花') zh('赵四','20','美炸一枝花')
那如果用面向对象的话:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class ZhaoSi: def __init__(self,name,age,): self.name =name self.age =age def cy(self): date = '%s今年%s,他的相貌倾国倾城'%(self.name,self.age,) print (date) def by(self): date = '%s今年%s,他的相貌沉鱼落雁'%(self.name,self.age,) print (date) def zh(self): date = '%s今年%s,他的相貌美炸了花' % (self.name, self.age, ) print (date) obj = ZhaoSi('赵四','20') obj.cy() obj.by() obj.zh()
构造方式:
1.__init__特殊的方式这个叫做构造方法,目的就是为了目的的初始化
通过构造的方法可以将数据进行打包以后使用去里面获取即可.
2.应用:
好处:如果遇到很多相当的值,直接调用就可以了
A:将数据封装到对象中,以供自己在方法调用
B:对数据进行封装,给别人使用的时候 以供其他函数调用
练习:信息管理系统:
1.用户登录
2.查看用户信息
3.查看用户所有的账单
4.进行转账,购买了一个抱枕
如果这个类名+()方法就会自动执行
类的话对以后写代码方便,归类的话仁者见仁智者见智
方式一:归类+提取公共值
方式二:正向编写,某个类中编写和当中类中相关的所有代码
那么,面向对象有三大特性:封装,继承,多态
封装:
1.将相关的功能打包(封装)到一个类中
2.将数据封装到一个对象中
继承:
父类(基类)子类(派生类)
为什么要有继承?
是为了提高代码的重要性(复用)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class SuperBase: def f3(self): print('f3') class Base(SuperBase): # 父类,基类 def f2(self): print('f2') class Foo(Base): # 子类,派生类 def f1(self): print('f1') obj = Foo() obj.f1() obj.f2() obj.f3()
他没有就去找爸爸要,爸爸没有找爸爸的上一级爷爷要,是可以这么理解的~
python的话和其他语言不同的是,其实是可以有隔壁老王的,但是要继承的话左边优先选择,左边没有选择右边的
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class Base1: def show(self): print('Base1.show') class Base2: def show(self): print('Base2.show') class Foo(Base1,Base2): pass obj = Foo() obj.show()
总结:
1.继承编写
2.支持多继承(先左在右)c3算法
3.为了提高代码的复用性才要用多继承
练习部分:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class Base: def f1(self): print('base.f1') class Foo(Base): def f2(self): print('foo.f2') 1. 是否执行 obj = Foo() obj.f2() obj.f1() 2. 是否执行 obj = Base() obj.f1() obj.f2() # 错
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class Base: def f1(self): print('base.f1') def f3(self): print('foo.f3') class Foo(Base): def f2(self): print('foo.f2') self.f3() # obj是那一个类(Foo),那么执行方法时,就从该类开始找. obj = Foo() obj.f2() # obj是那一个类(Foo),那么执行方法时,就从该类开始找.
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class Base: def f1(self): print('base.f1') def f3(self): self.f1() # obj是那一个类(Foo),那么执行方法时,就从该类开始找. print('foo.f3') class Foo(Base): def f2(self): print('foo.f2') self.f3() # obj是那一个类(Foo),那么执行方法时,就从该类开始找. obj = Foo() obj.f2() # obj是那一个类(Foo),那么执行方法时,就从该类开始找.
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class Base: def f1(self): print('base.f1') def f3(self): self.f1() # obj是那一个类(Foo),那么执行方法时,就从该类开始找. print('base.f3') class Foo(Base): def f1(self): print('foo.f1') def f2(self): print('foo.f2') self.f3() # obj是那一个类(Foo),那么执行方法时,就从该类开始找. obj = Foo() obj.f2() # obj是那一个类(Foo),那么执行方法时,就从该类开始找. # foo.f2 # foo.f1 # base.f3 obj2 = Base() obj2.f3() # base.f1 # base.f3
总结: self是那个类的对象,那么就从该类开始找(自己没有就找父类)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class Base1: def f1(self): print('base1.1') def f2(self): print('base1.f2') class Base2: def f1(self): print('base2.f1') def f2(self): print('base2.f2') def f3(self): print('base2.f3') self.f1() class Foo(Base1,Base2): def f0(self): print('foo.f0') self.f3() # 1. 多继承先找左边 # 2. self到底是谁,self是那个类的对象,那么就从该类开始找(自己没有就找父类) obj = Foo() obj.f0()
还有一个多态:
这个就是最有名的鸭子模型:我把你的眼睛蒙上,拿一只鸭子让他叫,蒙上你的眼睛,只要嘎嘎叫的就是鸭子
但是由于python原生支持多态,所以木有什么特殊性,但是在java里是多态很重要的~