一、上节回顾:
复习:
面向对象的三大特性: 继承 多态 封装
(1)继承:
#单继承:最常用的
#多继承:钻石继承问题提现差别:经典类(深度优先)和新式类(广度优先),mro
#新式类:super
#父类子类调用方法的先后顺序
#只要子类有就用子类的,子类没有就找父类
#子类父类都想用,就先找子类,在子类中调用父类( super().hahaha() )
#在多继承中,super不只是寻找当前的父类,而是依据mro顺序,
#从A节点出发,依据广度优先排序查找下一类
、 #派生:子类中可能有,派生属性和派生方法
#多态和鸭子类型
class Teacher: pass class School: pass class Professor(Teacher,School): pass p1=Professor() print(Professor.mro())
class Parentclass1: #定义父类(基类或者超类) pass class Parentclass2: #定义父类 pass class SubClass1(Parentclass1): #单继承,基类是Parentclass1,派生类SubClass1 pass #新建的类叫做派生类或者子类 class SubClass2(Parentclass1,Parentclass2): #多继承 pass
#查看继承 print(SubClass1.__bases__) #__base__只查看从左到右继承的第一个子类,__bases__则是查看所有继承的父类 print(SubClass2.__bases__)
#继承和抽象
#抽象最主要的作用是划分类别,抽象只是分析和设计的过程
#继承:是基于抽象的结果,通过编程语言去实现它,
# 肯定是先经历抽象这个过程,才能通过继承的方式去表达抽象的结构
# 继承和重用性 class Animal: def eat(self): print("%s 吃"%self.name) def drink(self): print("%s 喝"%self.name) def shit(self): print("%s 拉"%self.name) def pee(self): print("%s 撒"%self.name) class Cat(Animal): def __init__(self,name): self.name=name self.breed="猫" def cry(self): print("喵喵叫") class Dog(Animal): def __init__(self,name): self.name=name self.breed="狗" def cry(self): print("汪汪叫") ##########执行######## c1=Cat("小白家的小黑猫") c1.eat() c2=Cat("小黑家的小白猫") c2.drink() d1=Dog("胖子家的小瘦狗") d1.eat()
通过继承的方式新建类B,让B继承A,B会‘遗传’A的所有属性(数据属性和函数属性),实现代码重用
class Animal: def __init__(self,name,aggressivity,life_value): self.name=name self.aggressivity=aggressivity self.life_value=life_value def eat(self): print("%s is eating"% self.name) class Dog(Animal): pass class Person(Animal): pass egg=Person("egon",10,1000) ha2=Dog("二愣子",50,1000) egg.eat() ha2.eat()
派生(子类):
class Animal: """ 人和狗都是动物所以创造一个Animal基类 """ def __init__(self,name,aggressivity,life_value): self.name=name #人和狗都有自己的昵称 self.aggressivity=aggressivity #人和狗都有自己的攻击力 self.life_value=life_value #人和狗都有自己的生命值 def eat(self): print("%s is eating"% self.name) class Dog(Animal): """ 狗类,继承Animal类 """ def bite(self,people): """ 派生:狗有咬人的技能y :param people: :return: """ people.life_value-=self.aggressivity class Person(Animal): def attack(self,dog): """ 派生:人有攻击狗的技能 :param dog: :return: """ dog.life_value-=self.aggressivity pass egg=Person("egon",10,1000) ha2=Dog("二愣子",50,1000) print(ha2.life_value) egg.attack(ha2) print(ha2.life_value)
super:
在python3中,子类执行父类的方法也可以直接用super方法.
class A: def hahaha(self): print("A") class B(A): def hahaha(self): super().hahaha() #super(B,self).hahaha() #A.hahaha(self) print("B") a=A() b=B() b.hahaha() #A B super(B,b).hahaha() #A
派生:
class Animal: """ 人和狗都是动物所以创造一个Animal基类 """ def __init__(self,name,aggressivity,life_value): self.name=name #人和狗都有自己的昵称 self.aggressivity=aggressivity #人和狗都有自己的攻击力 self.life_value=life_value #人和狗都有自己的生命值 def eat(self): print("%s is eating"% self.name) # class Dog(Animal): """ 狗类,继承Animal类 """ def __init__(self,name,breed,aggressivity,life_value): super().__init__(name,aggressivity,life_value) #执行父类Animal的init方法 self.breed=breed #派生出了新属性 def bite(self,people): """ 派生:狗有咬人的技能y :param people: :return: """ people.life_value-=self.aggressivity def eat(self): #Animal.eat(self) #super().eat() print("from Dog") class Person(Animal): """ 人类,继承Animal类 """ def __init__(self, name,aggressivity, life_value,money): #Animal.__init__(self,name,aggressivity,life_value) #super(Person,self).__init__(name,aggressivity,life_value) super().__init__(name, aggressivity, life_value) # 执行父类Animal的init方法 self.money = money # 派生出了新属性 def attack(self,dog): """ 派生:人有攻击狗的技能 :param dog: :return: """ dog.life_value-=self.aggressivity def eat(self): # super().eat() Animal.eat(self) print("from Person") egg=Person("egon",10,1000,600) ha2=Dog("二愣子","哈士奇",50,1000) print(egg.name) print(ha2.name) egg.eat() egg.attack(ha2) print(ha2.life_value)
通过继承建立了派生类与基类之间的关系,它是一种'是'的关系,比如白马是马,人是动物。
当类之间有很多相同的功能,提取这些共同的功能做成基类,用继承比较好,比如教授是老师
class Teacher: def __init__(self,name,gender): self.name=name self.gender=gender def teach(self): print("teaching") class Professor(Teacher): pass p1=Professor("egon","male") p1.teach() # teaching
(2)多态:
一种事物的多种形态叫做多态
class Animal:pass class Dog(Animal):pass class Cat(Animal):pass
(3)鸭子类型:
#对于某一些方法来说,可以无差别的对待几个类型就是鸭子类型
#python 不崇尚数据类型之间的继承关系
#数据类型之间减少依赖关系,解耦
#写功能性的程序:以功能为导向
#写框架类的,或者模块类的,使用继承的同时还要考虑解耦
二、今日内容 :
抽象类和接口类:
(1)不崇尚接口类
(2)python本身支持多继承,没有接口专用的语法,但是我知道接口的概念
封装:
(1)私有属性
(2)将方法转换成属性的机制:@property
(3)@classmethond @staticmethod
1、接口类
#接口类
#继承有两种用途:
# 一、继承基类的方法,并且做出自己的改变或者拓展(代码重用)
#二、声明某个子类兼容于某基类,定义一个接口类interface,接口类中定义了一些接口名
# (就是函数名)且并未实现接口的功能,子类继承接口类,并且实现接口中的功能
最基础的接口类(但是容易出问题)
class Alipay: """ 支付宝支付 """ def pay(self,money): print("支付宝支付了%s元"%money) class Applepay: """ apple pay 支付 """ def pay(self,money): print("apple pay 支付了%s元"%money) def pay(payment,money): """支付函数,总体负责支付 对应支付的对象和要支付的金额 """ payment.pay(money) p=Alipay() p1=Applepay() pay(p,200) #支付宝支付了200元 pay(p1,2000) #apple pay 支付了2000元
接口初成:手动报异常
class Payment: def pay(self): raise NotImplementedError class Wechatpay(Payment): def fuqian(self,money): print("微信支付了%s元"%money) p=Wechatpay() #这里不报错 pay(p,200) #这里报错了
接口编程:是依赖模板进行编程
from abc import ABCMeta,abstractmethod #接口类,是规范子类的一个模板,只要接口类中定义的,就应该在子类中实现 class Payment(metaclass=ABCMeta): #模板,接口类 @abstractmethod #装饰器接口类中的方法的,加上这个装饰器,自动检测子类中的方法名 def pay(self,money): pass class Ali_Pay(Payment): def pay(self,money): print("您使用的支付宝支付了%s元"%money) class Apple_Pay(Payment): def pay(self,money): print("您使用的苹果支付了%s元"%money) class Wechat_Pay(Payment): def pay (self,money): print("微信支付了%s元"%money) def pay(obj,money): return obj.pay(money) # apple=Apple_Pay() # ali=Ali_Pay() wechat=Wechat_Pay() # pay(apple,100) #apple.pay(100) pay(wechat,200) #微信支付了200元
from abc import ABCMeta,abstractmethod class Fly_Animal(metaclass=ABCMeta): @abstractmethod def fly(self):pass class Swim_Animal(metaclass=ABCMeta): @abstractmethod def swim(self): pass class Walk_Animal(metaclass=ABCMeta): @abstractmethod def walk(self): pass class Frog(Walk_Animal,Swim_Animal): def walk(self): print("实现walk功能") class Swan(Walk_Animal,Swim_Animal,Fly_Animal):pass class Bird(Swim_Animal,Fly_Animal):pass
接口隔离原则:使用多个专门的接口,而不使用单一的总接口,而客户端不应该依赖那些不需要的接口
#一切皆文件 import abc #利用abc模块实现抽象类 class All_file(metaclass=abc.ABCMeta): all_type="file" @abc.abstractmethod #定义抽象方法,无序实现功能 def read(self): # ‘子类必须定义读功能’ pass @abc.abstractmethod #定义抽象方法,无序实现功能 def read(self): # ‘子类必须定义写功能’ pass class Txt(All_file): #子类继承抽象类,但是必须定义read和write方法 def read(self): print("文本数据的读取方法") def write(self): print("文本数据的读取方法") class Sata(All_file): #子类继承抽象类,但是必须定义read和write方法 def read(self): print("硬盘数据的读取方法") def write(self): print("硬盘数据的读取方法") class Process(All_file): #子类继承抽象类,但是必须定义read和write方法 def read(self): print("数据的读取方法") def write(self): print("进程数据的读取方法") wenbenwenjian=Txt() yingpanwenjian=Sata() jinchengwenjian=Process() #这样大家都是被归一化了,也就是一切皆文件的思想 wenbenwenjian.read() yingpanwenjian.write() jinchengwenjian.write() print(wenbenwenjian.all_type) print(yingpanwenjian.all_type) print(jinchengwenjian.all_type)
总结:
#接口类:
(1)是规范子类的一个模板,只要接口类中定义的,就应该在子类中实现
(2)接口类不能被实例化,它只能被继承
(3)支持多继承
#抽象类
(1)模板 规范
(2)抽象类可以实现一些子类共有的功能和属性\抽象类不鼓励多继承
文件操作:打开文件、关闭文件、写文件、读文件
硬盘操作:打开、关闭、读、写
进程文件:打开 关闭、读、写
(3)python没有接口概念,只能借助抽象类模块来实现接口类
接口————java:没有多继承 Interface
文件的抽象化
from abc import ABCMeta,abstractmethod class Base(metaclass=ABCMeta): def __init__(self,filename): self.filename=filename @abstractmethod #抽象方法 def open(self): return "file_handler" @abstractmethod def close(self):pass @abstractmethod def read(self): pass @abstractmethod def write(self): pass class File(Base): def open(self):pass def close(self):pass def read(self):pass def write(self):pass
2、封装
封装:把一些实行和方法放在类里,这本身就是一种封装
#封装:把属性和方法藏在类里,我只能在类内部调用,不能在外部使用
(1)私有变量
#其实这仅仅这是一种变形操作 #类内所有双下划线开头的名称如:__x都会自动变形成:_类名__x的形式: class A: __N=0 #类的数据属性就应该是共享的,但是语法上是可以把类的数据属性设置成私有的如__N,会变形为_A__N def __init__(self): self.__x=10 #变形为self._A__X def __foo(self): #变形为_A__foo print("from A") def bar(self): self.__foo() #只有在类内部才可以通过__foo的形式访问到 #A._A__N是可以访问到的,即这种操作并不是严格意义上的限制外部访问 #仅仅只是一种语法意义上的变形
调用类内的私有静态属性
class Dog: __role="dog" #私有的静态属性 def func(self): print(Dog.__role) #_类__名字 print(Dog.__dict__) # print(Dog._Dog__role) #不能这么调用 #从类的外面不能直接调用,在类内的使用加上了一层密码:_类名 d=Dog() d.func()
私有的方法
class Dog: __role="dog" #私有的属性 def __discount(self): #私有的方法 print("in__func") def price(self): self.__discount()
总结:定义一个私有变量\属性\方法:__名字
在类内部可以直接用:__名字
在类的外部不能直接使用,如果一定要用,在私有方法之前加上:_类名,变成_类名__名字
在类外的名字 通过__dict__就可以查看
例子:不需要的可以隐藏
class Room: def __init__(self,name,price,length,width): self.name=name self.price=price self.__length=length self.__width=width #隐藏的长与宽 def area(self): return self.__width*self.__length house=Room("小明",1000,22,33) print(house.area())
私有的不能被继承
class A: def __func(self): print("__a_func") #_A__func class B(A): def __init__(self): self.func() #_B__func b=B()
结果报错
总结:私有的静态属性、方法、对象属性
#使用__名字的方式调用,保证在类内部可以调用,外部不行
#私有的不能被继承
#当有一个名字。不想被外部使用,也不想被子类继承,只想在内部使用的时候就定义私有的
(2) property 是一种特殊属性,访问它时会执行一段功能(函数)然后返回
例一:BMI指数(bmi是计算而来的,但很明显它听起来像是一个属性而非方法,如果我们将其做成一个属性,更便于理解) 成人的BMI数值: 过轻:低于18.5 正常:18.5-23.9 过重:24-27 肥胖:28-32 非常肥胖, 高于32 体质指数(BMI)=体重(kg)÷身高^2(m) EX:70kg÷(1.75×1.75)=22.86
class Person: def __init__(self,name,height,weigth): self.name=name self.height=height self.weight=weigth def bmi(self): return self.weight/(self.height**2) li= Person("李",1.66,51) print(li.bmi())
#1)属性的值,是这个方法的返回值
#2)这个方法不能有参数
园的周长的例子:
import math class Circle: def __init__(self,radius): #圆的半径radius self.radius=radius @property def area(self): return math.pi * self.radius**2 #计算面积 @property def perimeter(self): return 2*math.pi*self.radius #计算周长 c=Circle(10) print(c.radius) print(c.area) #可以向访问数据属性一样去访问area,会触发一个函数的执行,动态计算出一个值 print(c.perimeter) #同上 ''' 输出结果: 314.1592653589793 62.83185307179586 '''
#注意:此时的特性area和perimeter不能被赋值 c.area=3 #为特性area赋值 ''' 抛出异常: AttributeError: can't set attribute '''
超市打折的例子: 修改原价,隐藏原价价格
class Goods: __discount=0.8 #静态属性 def __init__(self,name,price): self.name=name self.price=price #原价 @property def price(self): #折后价 return self.__price*Goods.__discount @price.setter #只能传一个参数 def price(self,new_price): #修改原价 self.__price=new_price if type(new_price) is int: #座一次限制后,下面的价格修改就会变得安全 self.__price=new_price apple=Goods("苹果",10) print(apple.price) danana=Goods("香蕉",2.5) print(danana.price) apple.price=5 print(apple.price)
总结: 封装
#__私有+property
#让对象的属性变得更安全了
#获取到的对象的值可以进行一些加工
#修改对象的值的同时可以进行一些验证
补充: setter和 property
class Foo: @property def AAA(self): print("get的时候运行我啊") @AAA.setter def AAA(self,value): print("set的时候运行我啊") @AAA.deleter def AAA(self): print("delete的时候运行我啊") #只有在属性AAA定义property后才能定义AAA.setter,AAA.deleter f1=Foo() f1.AAA f1.AAA="aaa" del f1.AAA
怎么用:
class Goods: def __init__(self): # 原价 self.original_price = 100 # 折扣 self.discount = 0.8 @property def price(self): # 实际价格 = 原价 * 折扣 new_price = self.original_price * self.discount return new_price @price.setter def price(self, value): self.original_price = value @price.deleter def price(self): del self.original_price obj = Goods() obj.price # 获取商品价格 obj.price = 200 # 修改商品原价 print(obj.price) del obj.price # 删除商品原价
关于删除:
class Goods: __discount=0.8 def __init__(self,name,price): self.__name=name self.__price=price @property def name(self): return self.__name @name.setter def name(self,new_name): self.__name=new_name @name.deleter def name(self): del self.__name @property def price(self): return self.__price*Goods.__discount @price.setter def price(self,new_price): if type(new_price)is int: self.__price=new_price apple=Goods("苹果",10) # del apple.name print(apple.name)
(3)类方法
@classmethod
class Goods: __discount=0.8 @classmethod #类方法 def change_discount(cls,new_discount): cls.__discount=new_discount*0.5 @classmethod def get_discount(cls): return cls.__discount # apple=Goods() Goods.change_discount(0.75) print(Goods.get_discount())
总结:
类方法:
#调用:不需要实例化,直接用类名调用就好
#定义:不用接受self参数,默认传cls,cls就代表当前方法所在的类
#什么时候用类方法?
#需要使用静态变量 且不需要和对象相关的任何操作 就使用静态方法
(4)静态方法
@staticmethod
class A: @staticmethod def func(name): print(123) A.func("alex")
总结:面向对象的编程:专门为面向对象编程提供的一个方法————staticmethod
#它完全可以当做普通的函数去用,只不过这个函数需要通过类名.函数名调用
#其他 传参 返回值 完全没有区别
绑定和非绑定:
class A: @staticmethod def func1(name): print(123) @classmethod def func2(name): print(123) def func3(self):pass a=A() print(a.func1) #静态方法 print(a.func2) #类方法:找到绑定到A类的func print(a.func3) #普通方法:绑定到A类对想的func
在类里面,一共可以定义这三种方法:
普通方法 self
类方法 cls @classmrthod
静态方法 @staticmethod
静态方法和类方法都是直接使用类名调用
普通方法:对象调用