python面向对象 : 抽象类(接口类),多态,封装(私有制封装)
一. 抽象类(接口类)
与java一样, python也有抽象类的概念但是同样需要借助模块实现,抽象类是一个特殊的类, 它的特殊之处在于只能被继承, 不能被实例化.
从设计角度去看, 如果类是从现实对象抽象而来的, 那么抽象类就是基于类抽象而来的。
从实现角度来看, 抽象类与普通类的不同之处在于: 抽象类中有抽象方法, 该类不能被实例化, 只能被继承, 且子类必须实现抽象方法. 这一点与接口有点类似, 但其实是不同的.
实现不同的支付方式:
class Alipay: def __init__(self, money): self.money = money def alipay(self): print('使用支付宝支付了%s元' % self.money) class Jdpay: def __init__(self, money): self.money = money def jdpay(self): print('使用京东支付了%s元' % self.money) a = Alipay(500) a.alipay() # 使用支付宝支付了500元 j = Jdpay(200) j.jdpay() # 使用京东支付了200元
虽然都实现了支付,但是两个支付都是相同的功能,但调用方却不一样,可以把调用方设置一样.
class Alipay: def __init__(self, money): self.money = money def pay(self): print('使用支付宝支付了%s元' % self.money) class Jdpay: def __init__(self, money): self.money = money def pay(self): print('使用京东支付了%s元' % self.money) def pay(obj): obj.pay() a = Alipay(500) pay(a) # 调用函数pay,把对象a穿进去,并执行函数语句 j = Jdpay(200) pay(j) # 调用函数pay,把对象j穿进去,并执行函数语句 # 调用方都是函数pay 归一化设计
虽然设置了一个pay函数,但是有可能后面接手你程序的人并不会发现,含是按照第一种的方法实现新的支付方式,所以我们要确保在之后添加的类中要有pay函数.
from abc import ABCMeta, abstractmethod # 从abc模块引进ABCMeta,abstractmethod class Allpay: @abstractmethod # 在需要制定模板的函数上写一句 def pay(self): # 制定规范,子类中必须有pay方法,否则报错 pass class Alipay(Allpay): def __init__(self, money): self.money = money def pay(self): print('使用支付宝支付了%s元' % self.money) class Jdpay(Allpay): def __init__(self, money): self.money = money def pay(self): print('使用京东支付了%s元' % self.money) class Wechatpay(Allpay): def __init__(self, money): self.money = money # def wechatpay(self): #函数名不是pay会报错 # pass def pay(self): print('使用微信支付了%s元' % self.money) def pay(obj): obj.pay() a = Alipay(500) pay(a) # 使用支付宝支付了500元 j = Jdpay(200) pay(j) # 使用京东支付了200元 w = Wechatpay(700) pay(w) # 使用微信支付了700元
二. 多态
python不支持多态, 也不用支持多态,因为python处处是多态, python是一种多态语言, 参数在传入之前是无法确定参数类型的. 崇尚鸭子类型
鸭子类型 : 看着像鸭子,他就是鸭子, 下面的类有相同功能的方法, 都互称为鸭子.
class Str: def index(self): pass class List: def index(self): pass class Tuple: def index(self): pass
三. 封装
封装,顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容。所以,在使用面向对象的封装特性时,需要:将内容封装到某处, 然后从某处调用被封装的内容.
封装分为广义的封装和狭义的封装
广义的封装: 实例化一个对象,给对象空间封装一些属性.
class Animal: def __init__(self,name,sex,age): self.name = name #广义的封装 self.age = age self.sex = sex
狭义的封装: 私有制.
私有成员 : 私有静态字段, 私有方法, 私有对象属性
私有静态字段:
在类外部引用私有静态字段
class Pay: __money = 1000 # 定义私有静态变量__money def pay(self): pass p = Pay() p.__money # 报错,在类外部对象无法引用私有静态字段__money Pay.__money # # 报错,在类外部类名无法引用私有静态字段__money
在类内部引用私有静态字段
class Pay: __money = 1000 # 定义私有静态变量__money def pay(self): print(p.__money) # 在类内部对象可以引用私有静态字段__money print(Pay.__money) # 在类内部类名可以引用私有静态字段__money p = Pay() p.pay() # 1000 # 1000
在子类引用私有静态字段
class Money: __money = 1000 # 定义私有静态变量__money class Pay(Money): def pay(self): pass print(p.__money) # 在子类内部对象不能引用父类的私有静态字段__money print(Pay.__money) # 在子类内部类名不能引用父类的私有静态字段__money p = Pay() # p.__money # 子类的对象无法引用父类的私有静态字段__money # Pay.__money # 子类名无法引用父类的私有静态字段__money p.pay()
总结:对于私有静态字段来说,只能在本类中内部访问,类的外部,派生类(子类)均不可访问.
# 可以访问,但是工作中千万不要用 : '__类名私有静态字段' # print(Pay._Pay__money) # print(Pay.__dict__)
私有方法:对于私方法来说,只能在本类中内部访问,类的外部,派生类(子类)均不可访问.
class B: def __f1(self): print('777') class A(B): def __func(self): print('666') def func1(self): self.__func() # 类内部可以访问 self.f1() # 子类无法访问父类的私有方法 a = A() # a.__func() # 类外部对象不能访问 # A.__func() # 类外部类名不能访问 a.func1() # 666 # 666
私有属性
class A: def __init__(self,name,age,weight): self.name = name self.__age = age self.__weight = weight def func(self): print(self.__age) #类内可以引用私有属性 a1 = A('jsck',18,45) print(a1.name) print(a1.__dict__) # {'name': 'jsck', '_A__age': 18, '_A__weight': 45} # print(a1.__age) # 类外无法引用私有属性 a1.func()
面试题
class Parent: def __func(self): print('in Parent func') def __init__(self): # 自动执行__init__方法 self.__func() # self.__func() =>> self.__Parent__func class Son(Parent): def __func(self): print('in Son func') son1 = Son() # in Parent func