抽象类,接口类,封装,property,classmetod,statimethod
抽象类,接口类,封装,property,classmetod,statimethod(类方法,静态方法)
一丶抽象类和接口类
接口类(不崇尚用)
接口类:是规范子类的一个模板,只要接口类中定义的,就应该在子类中实现
接口类不能被实例化,只能被继承
支持多继承,父类不实现
python 本身支持多继承,没有接口专用的语法。但是得知道接口的概念
例子:
class Alipay: ''' 支付宝支付 ''' def pay(self,money): print('支付宝支付了%s元'%money) class Applepay: ''' apple pay支付 ''' def pay(self,money): print('apple pay支付了%s元'%money) class Wechatpay: def fuqian(self,money): ''' 实现了pay的功能,但是名字不一样 ''' print('微信支付了%s元'%money) def pay(payment,money): ''' 支付函数,总体负责支付 对应支付的对象和要支付的金额 ''' payment.pay(money) p = Wechatpay() pay(p,200) #执行会报错
第一种解决方式(比较low)
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 # 接口类: # 是规范子类的一个模板,
# 只要接口类中定义的,就应该在子类中实现(规范所有支付功能必须实现pay方法) # 接口类不能被实例化,它只能被继承 # 支持多继承 class Payment(metaclass=ABCMeta): #模板,接口类 @abstractmethod #装饰接口类中方法的,加上这个装饰器,自动检测子类中的方法名 def pay(self,money):pass @abstractmethod def get(self):pass # 收钱功能 class Apple_Pay(Payment): def pay(self,money): print('您使用苹果支付支付了%s元'%money) class Ali_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)
#接口类 : 多继承,父类不实现 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功能') def swim(self): pass class Swan(Walk_Animal,Swim_Animal,Fly_Animal): pass class Bird(Walk_Animal,Fly_Animal): pass
接口隔离原则: 使用多个专门的接口,而不使用单一的总接口。即客户端不应该依赖那些不需要的接口。
抽象类
抽象类可以实现一些子类共有的功能和属性\抽象类不鼓励多继承
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 # 抽象类不能被实例化 # 这个抽象类可以规范子类必须实现抽象类中的抽象方法
二、封装(重要)
封装: 隐藏对象的属性和实现细节,仅对外提供公共访问方式
把一些属性和方法放到类里 这本身就是一种封装(广义上的封装)
面对对象里的封装 : 把属性和方法藏在类里 我只能在类内部调用,不能再外部使用(实际意义)
好处:
1. 将变化隔离; 2. 便于使用;3. 提高复用性; 4. 提高安全性;
原则:
1. 将不需要对外提供的内容都隐藏起来;
2. 把属性都隐藏,提供公共方法对其访问。
加__藏起来 class Dog: __role = 'dog' # 私有的静态属性,在语法上是可以把类的数据属性设置成私有的如__N,会变形为_Dog__N def func(self): # 内部使用 print(Dog.__role) # _Dog__role 私有方法 # print(Dog.role) print(Dog.__dict__) # 查看名字空间 print(Dog._Dog__role)# 不鼓励这样调用私有变量 dog 查私有静态属性 从类的外面不能直接调用,在类内的使用加上了一层密码:_类名 d = Dog() #能实例化 d.func()
私有动态方法 class Dog: __role = 'dog' # 私有的静态属性 def __discount(self): print('in __func') # 私有方法 (动态) def price(self): self.__discount() print(Dog.__dict__) print(Dog._Dog__discount)
定义一个私有变量\属性\方法:__名字
在类的内部可以直接使用: __名字
在类的外部不能直接使用,如果一定要用,在私有方法之前加上:_类名,变成_类名__名字 # 不推荐使用
在类外的名字 通过__dict__就可以查看
私有的
私有的静态属性、方法、对象属性
使用__名字的方式调用,保证在类内部可以调用,外部不行
class Room: def __init__(self,name,price,length,width): self.name = name self.price = print self.__length = length # 私有的对象属性 self.__width = width def area(self): return self.__length*self.__width house = Room('天空之镜',100000,200,1) 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() # 报错
三、property内置(会使代码变整洁)
property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值
例子:1、
@property 把一个方法 伪装成一个属性
1 属性的值 是这个方法的返回值
2 这个方法不能有参数
class Person: def __init__(self,name,height,weight): self.name = name self.height = height self.weight = weight # @property 加了方法变属性 def bmi(self): #bmi人的一个属性 self.weight/(self.height ** 2) li = Person('lishi',1.65,50) print(li.bmi) # 属性 print(li.bmi()) # 方法
2、
圆形类 from math import pi class Circle: def __init__(self, r): self.radius = r @property def perimeter(self): return 2 * pi * self.radius @property def area(self): return pi * (self.radius ** 2) c1 = Circle(5) print(c1.area)
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 apple = Goods('榴莲',10) print(apple.price) # 8.0 banana = Goods('香蕉',2.5) print(banana.price) 2.0 apple.price = 6 # 修改不了原价 print(apple.price) # 报错
解决:setter
class Goods: discount = 0.8 # 静态属性 全部打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): # 修改原价
# if type(new_price) is int: # 加了,可以增加安全性,使用setter的优势 self.__price = new_price # self.__price = new_price apple = Goods('苹果',20) # 原价
apple.price = 10 # 修改原价(只能传一个参数) setter print(apple.price) # property
封装 __私有+property 让对象的属性变得更安全了 获取到的对象的值可以进行一些加工 修改对象的值的同时可以进行一些验证 setter
一个静态属性property本质就是实现了get,set,delete三种方法
class Foo: @property # 把AAA伪装成一个属性 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 Foo: def get_AAA(self): print('get的时候运行我啊') def set_AAA(self,value): print('set的时候运行我啊') def delete_AAA(self): print('delete的时候运行我啊') AAA=property(get_AAA,set_AAA,delete_AAA) #内置property三个参数与get,set,delete一一对应 f1=Foo() f1.AAA f1.AAA='aaa' del f1.AAA
使用:
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) # 报错,已删除
四、classmethod和staticmthod(类方法、静态方法)
问题:定义一个类类里面的方法并没有用到self
例如:
# 与apple无关,所以def change_discount(self,new_discount)在这里不适合
# 需实例化 class Goods: __discount = 0.8 def change_discount(self,new_discount): Goods.__discount = new_discount apple = Goods() # 实例化 apple.change_discount(0.75)
修改版
类方法:
class Goods: __discount = 0.8 @classmethod #类方法 def change_discount(cls,new_discount): cls.__discount = new_discount @classmethod def get_discount(cls): return cls.__discount # apple = Goods() Goods.change_discount(0.75) print(Goods.get_discount())
类方法好处:
调用:不需要实例化 直接用类名调用就好
定义:不用接受self参数,默认传cls,cls就代表当前方法所在的类
什么时候用类方法?
需要使用静态变量 且 不需要和对象相关的任何操作的时候
静态方法:
如果这个方法 既不需要操作静态变量也不需要使用对象相关的操作,就使用静态方法
class A: @staticmethod def func(name): #静态方法 print(123) A.func('alex')
class A: @staticmethod def func(): #静态方法 print(123) A.func()
面向对象编程:专门为面向对象编程提供的一个方法——staticmethod
它完全可以当做普通函数去用,只不过这个函数要通过类名.函数名调用
其他 传参 返回值 完全没有区别
类里面,一共可以定义这三种方法:
普通方法 self
类方法 cls @classmrthod
静态方法 @staticmethod
绑定方法 和 非绑定方法 class A: @staticmethod def func1(name): #静态方法 print(123) @classmethod def func2(cls): # 静态方法 print(123) def func3(self):pass a = A() print(a.func1) #静态方法 print(a.func2) #类方法 : 绑定到A类的func print(a.func3) #普通方法:绑定到A类对象的func
静态方法和类方法 都是直接可以使用类名调用
普通方法:对象调用
类能解决的事,没必要搞个实例化对象能弄