一、面向对象和面向过程
一、什么是面向过程
核心是过程二字:面向过程是一种流水线的工作流程,是先做什么在做什么
二、什么是面向对象
核心 是对象二字:是一种编程思想,上帝思维,一切皆对象,编程中负责调度和控制
三、面向对象与面向过程的优缺点
面向过程:
优点:程序逻辑性强;复杂的问题简单化
缺点:维护性差;功能拓展性差
面向对象:
优点:功能拓展性强;维护性高,复用性强
缺点:代码的复杂度提高了
四、如何创建类和对象
2.0 语法
class A:
def __init__(self,name,age):
self.name = naem
self.age = age
a1 = A() # 类型加括号在初始化阶段自动触发__init__() 方法创建一个空对象, 只有当传值的时候才会再次触发__init__()函数的方法,将对象进行初始化赋值 >>> 实列化产生对象的过程
2.1 如何设置属性
类下的属性是按照对象的需求进行创造的 ,对象需要什么叫设置什么属性
2.2 属性的查找顺序
优先找自己> 所在的类>父类
2.3 对象的初始化方法
2.4 绑定方法与非绑定方法
1.绑定给对象的方法,有在对象初始化的时候 2.类中函数的方法是默认绑定给对象用的会默认将实例化的对象传过去当做函数的第一参数,会用变量名 self 接收
2.当我们需要调用类使用函时加@classmethod 装饰器下面的函数会自动将<类>作为第一参数传过来 此时是默认绑定给类用的函数
3.@statimethod 静态方法 不需要传参数使用就绑定给谁
二、面向对象三大特性
一、继承
二、封装
三、多态
一、继承
1、什是继承
定义:描述的是什么 是什么的关系,在程序中描述的是类与类之间的关系,他们之间是存在一定关系的
super()方法
如果你继承一个已有的类,并且你覆盖了init 一定要先调用父类的init
子类访问父类的属性和方法:先找自己的>所在类>父类>object oject 是所有类的基类
2、为什用继承:
原因:子类可以使用父类所有未被封装的属性和方法 ,提高代码的重用性,不需要在子类中重写__init__ 方法》》》实列化的初始赋值
3、继承语法
a 继承了b 那么b 就是a 的父类 a 就可以继承父类b 的所有属性和未被封装的方法与数据属性
4、先抽象在继承
其实就是一个抽取相同属性和共用方法的 过程,这个过程是抽象
classA:
name= 'alice'
def __init__(self, name, age):
self.name=name
self.age=ageclassB(A):passa1= A()
5、组合 什么没有什么的关系
定义:把一个对象当做另一个对象的属性 这两不存在任何的关系 不是继承
是为了使用它的属性和功能
classDate:def __init__(self,year, month,day):
self.year=year
self.month=month
self.day=daydefinfo(self):print('我是date里的函数')classTeacher:def __init__(self,name, age, num,date):
self.name=name
self.age=age
self.num=num
self.date=datedefchange_score(self):print('修改分数')classStudent:def __init__(self,name,date):
self.date=date
self.name=namedefchoice(self):print('选择')
d1= Date(2019,7,27)print(d1.year)print(d1.month)print(d1.day)#s1 = Student('koko') # koko想修改分数 或则拿到日期 没办法调
s2= Student('koko',d1)print(s2.date.year)print(s2.date.month)print(s2.date.day)
s2.date.info()#类内函数直接执行调用,不需要加括号打印,没有返回值None 除非自己设置了return值
t1= Teacher('lire',18,10,d1)print(t1.date.year)
t1.date.info()
>>>>>
2019
7
27
2019
7
27
我是date里的函数
2019
我是date里的函数
6、派生
派是子类继承父类方法和属性时,自己有重新定义了新的属性和方法
用的时候优先使用自己的,自己没有才会使用父类的
7、·覆盖
子类在继承父类时 自己有重新定义的属性和方法 自己的属性和方法和父类的名字一模一样
9、新式类和经典类
新式类:默认继承object 类的叫新式类
python 中默认是新式类 没有经典类
经典类:没有继承oject 类的叫经典类 python2中是用的经典类
10、菱形继承mro :c3算法
类在查找=顺序的时候会按照mro 的查找,深度优先,如果在查找的过程中遇到几个类同时继承一个父类广度优先
二、封装
2.1何为封装
1.定义:将丑陋的复杂的,隐私的细节隐藏到内部,对外部提供简单的使用接口
对外隐藏内部实现,提供函数访问的简单的接口2.目的:1.为了保证数据的安全性2.对外隐藏实现细节,隔离复杂度()主要原因就是隔离复杂度)3.什么时候用:1、当有一些数据不希望外界可以直接使用2.当有一些函数不希望给外界使用
4.语法:__属性名在实列化赋初值
##### 被封装的内容的特点:
1.外界不能直接访问
2.内部依然可以使用 通过设定函数调用查询##
2.3 封装的语法
classPerson:
def __init__(self, name, age, id_number):
self.name=name
self.age=age
self.__id_number= id_number
2.4 封装的原理:变量在类实列化对象进行初始值赋值的时候就已经将我们隐藏的self._name 封装成为_父类名__变量名 说以外部在没有调用函数的基础下,再次用对象点__name 是根本不可能访问他的名字的
2.5 访问私属性的方法:装饰器
classPerson:
def __init__(self, name, age, id_number):
self.name=name
self.age=age
self.__id_number=id_number
@property
def id_number(self):returnself.__id_number
p1= Person('coco', 18, 6666) # 类生成对象初识化 赋值 将产生的变量存放在名称空间中 所以绑定关系在初始化的时候已经确定了
# 封装是将隐藏的属进行封装
方法:
1.如果想要访问内部已经封装的属性一是可以在类的属性下进行定义一个函数 在函数 内返回 我们的要查找我们封装好的变量名
def id_number(self):
returnself.__id_number
2. 加@property也是一样的内部代码必须设计返回我们需要查找的数据属性
为什么要使用@property
# 对于一写封装的属性如何取值 和修改以及删除classIphone:
def __init__(self,kind, price, red):
self.__kind=kind
self.__price=price
self.__red=red
# 方法red ,kind , price
@property
def red(self):returnself.__red
@red.setter
def red(self,new_color):
self.__red=new_color
IP= Iphone('苹果', 4888, '红色')
# print(IP.red()) # 函数可以直接访问内部封装的东西
# print(IP.__red) # 现在没有办法获取 怎么办呢>>>可以@Property鸭 这样就相当于IP.red 伪装成对象点.red
print(IP.red)
IP.red= '绿色'# print(IP.red)
# print(IP.red)
# print(IP.red)
# print(IP.red)
print(IP.red) # 绿色 夹装饰器是为了可以可以在外部修改和查看内部的属性和调用方法
原因是:设计是将函数名设计成和我们要所要访问的变量名一模一样>>>加@property后就可以直接对象点函数形
其实就是伪装让外部觉得他直接对象点变量名的拿到的变量名指向的内存空间的值,实际情况是我们对外提供了接口,封装了我们的在内部实现细节。
如何访问私有化的函数:被封装了的函数
#目的不让外部修改内部属性和方法
classPerson:def __init__(self, name, age, id_number):
self.name=name
self.age=age
self.__id_number =id_number
@propertydefid_number(self):return self.__id_number
def __run(self): #如何访问封值装私有化的函数 __run实质变形为:_所属的类名__函数名
print('running')print('密码》》》009')def bar(self,y): #好简单 在函数内部在定义一个函数 他的返回结果就是封装的函数 可以拿到里面的代码执行的内容
if y < 100:return self.__run()
>>>>
好简单 在函数内部在定义一个函数 他的返回结果就是封装的函数 可以拿到里面的代码执行的内容
封装原理:
__run实质变形为:_所属的类名__函数名
p1._Person__run() # 私有化原理
p1.bar(70) # 通过定义一个新的函数访问 设置返回值
2.6.封装计算属性
#1.计算一个元或者一个长方形的面积
# 计算一个元或者一个长方形的面积classRadio:
def __init__(self,r=10):
self.__r=r
#计算周长
@property
def r(self):returnself.__r
@r.setter
def r(self, new_r):
self.__r=new_r
#计算面积
def ares(self):return 3.14*self.__r**2r1=Radio()
res1=r1.ares()
print(res1)
r1.r= 20# r2= Radio(20) # 内部我们限定死了 所以没有办法更改 怎么办
res=r1.ares()
print(res)
# 现在想把我的 可以通过外部进行改值
# print(r1.R())
# print(r2.R())
print(Radio.__dict__)
2. 计算BMI
#练习: 定义一个类叫做person#包含三个属性 身高 体重 BMI#BMI的值需要通过计算得来 公式 体重 / 身高的平方
classBaseClass:def __init__(self, high, weight,):
self.high=high
self.weight=weightdefBMI(self):#公式:BMI = 体重(KG)/身高(m)的平方
return self.weight/self.high**2
#实列化对象
person1= BaseClass(1.65, 62)print(person1.BMI())"""当BMI指数为18.5~23.9时属正常。
成人的BMI数值标准:
过轻:低于18.5 正常:18.5-23.9
过重:24-27 肥胖:28-32"""
2.7 鸭子类型
接口
何为接口:就是如USB接口提供一套统一标准的协议只要你遵循use制定的接口协议,你的设备尽可以通过使用usd 的功能 就可以连入电脑 进项相关操作
#接口:USB提供了一套统一的标准的也称为协议,只要你遵循的这条套协议你的设备就可以连入电脑使用,不管你是 鼠标还是键盘都可以被识操作电脑
classMouse:defopen(self):print('鼠标打开电脑')defclose(self):print('鼠标关闭了')defread(self):print('鼠标获取关光标')defwrite(self):print('鼠标不支持写')defpc(usb_server):
usb_server.open()
usb_server.close()
usb_server.write()
usb_server.close()
m=Mouse()
pc(m)#这是外部函数加括号进行传参
classKeyBord:defopen(self):print('键盘打开。。。')defclose(self):print('键盘关机了。。。')defread(self):print('获取按键字符。。')defwrite(self):print('键盘写入信息')#鸭子类型属性也像都很像,方法有像 所以叫做鸭子类型
k=KeyBord()
pc(k)classUdisk:defopen(self):print('u盘启动了')defclose(self):print('U盘关闭')defread(self):print('读出数据')defwrite(self):print('写入数据')
u=Udisk()
pc(u)
抽象 类
定义:abc 抽象类 就是函数体内没有函数体代码 没有任何函数体 定义函数功能 没有函数内容
# 强制要求子类的函数功能和父类功能一模一样, 但是我们根据需求可以在子类函数体内 定义添加功能其他功能代码 抽象类就但是一套统一的接口 要用我的东西 可以 但必须遵循我的协议标准
#接口和抽像类:#何为接口:是一套协议规范,明确子类们应该具备哪些功能,#抽象类是用于强制要求字类必须按照协议中规定的来实现,python 中不推崇
#鸭子类型:既可让多个不同类对象具备相同属性和方法对于使用者而言,就可以以不变应万变,轻松的使用各种对象
"""abc
抽象类的定义:类中包含没有函体的方法"""
importabcclass AClass(metaclass=abc.ABCMeta):
@abc.abstractmethoddefeat(self):pass@abc.abstractmethoddefeat1(self):pass
classGt(AClass):defeat(self):print('正在吃饭。。。。')defeat1(self):print('111111')whileTrue:
choice= input('调用此功能输入指令:').strip()if choice == '123456':print('yes')break
else:print('false')continueb= Gt() #无法用抽象方法eat1 去实列化抽象类Gt
b.eat1()
鸭子类型
一个类看起来像鸭子(属性),走起来也像(方法)就叫鸭子类型
然而,python 不推崇限制咱们的语法规则,我们可以设计成鸭子类型,即让多个不同类对象具备相同的属性和方法
对于使用者而言,就是可以以不变应万变。轻松的是使用各种对象
三、多态
3.1 定义:多个不同的类可以响同一个方法,产生不同的结果
首先强调多态不是一种特殊的语法,而是一种状态,特征(多个不同的类可以响同一个方法,产生不同的结果)
即多个对象有不同的使用方法
3.2优点:对于使用者而言大大的降低了使用难度
我们之前写的USB接口下的使用难度(鸭子类型)多的属于多态
3.3 接口,抽象类 都可以写出具备多态的代码,最简单的就是鸭子类型
案列:
#实列 多态其实就是不同事物可以使用同一种方法,但是产生的结果会不同(触发个方法的内部执行的内容不同)
classChicken:#同一方法
defdown(self):print('鸡下鸡蛋。。。')classDuck:defdown(self):print('鸭下鸭蛋。。。')classGoose:defdown(self):print('鹅下鹅蛋。。。')
鸡鸭鹅 都具有相同的功能,可以l利用实列化的对象 在内部封装一个调用接口
对象点自己内部的函数加 括号 执行对应的共能
#实列化对象
c =Chicken()
d=Duck()
g= Goose()
# 调用同一个方法
deffunc(obj):
obj.down()
func(c)
func(d)
func(g)