一、封装特性
(一)什么是封装
封装是将类中的某些部分隐藏起来,对象不能直接使用隐藏起来的属性或者方法,具有保护功能。
(二)私有属性
形如:__变量名,在类的外部不能使用(对象也不行)
class Girl():
def __init__(self,name,age):
self.name=name
self.__age=age
def show(self):
print(self.name,self.__age)
zs=Girl('张三',18)
zs.show()
print(zs.name)
print(zs.__age) # 报错 'Girl' object has no attribute '__age'
(三)私有化封装后的限制
实例:使用getXX()和setXX()方法来判断age属性的值是否为负数
class Girl():
def __init__(self):
pass
def setAge(self,age):
if age<0 or age>95:
print('错误')
self.age=0
else:
self.age=age
def getAge(self):
return self.age
zs=Girl()
zs.setAge(20)
print(zs.getAge()) # 20
zs.age=-9
print(zs.getAge()) # -9
zs.setAge(200)
print(zs.getAge()) # 0
这时就可以发现,可以通过对象在类外对之前的值进行覆盖,这就导致失去了setXX()中判断负数的意义。
这时候,就可以用私有属性来解决这个问题,代码如下:
class Girl():
def __init__(self,name,age):
self.name=name
self.__age=age
def setAge(self,age):
if age<0 or age>95:
print('错误')
self.__age=0
else:
self.__age=age
def getAge(self):
return self.__age
zs=Girl('张三',18)
zs.setAge(21)
print(zs.getAge()) # 21
print(zs.__dict__) # {'name': '张三', '_Girl__age': 21}
# 之前的值没有被覆盖
zs.__age=99
print(zs.getAge()) # 21
print(zs.__dict__) # {'name': '张三', '_Girl__age': 21, '__age': 99}
代码中,类外部的zs.__age=99中,__age不是类中的那个私有变量__age,而是另一个新的变量。
print(zs.__dict__)中,'_Girl__age:21'才是类中那个私有变量。
若想在类外对私有变量进行操作,可以使用_类名__变量名。知道有这种操作就可以,不支持这样使用:
class A():
def __init__(self,age):
self.__age=age
def setAge(self,age):
self.__age=age
def __str__(self):
return str(self.__age)
a=A(1)
a.__age=100
print(a.__dict__)
print(a._A__age)
a._A__age=99
print(a.__dict__)
结果:
{'_A__age': 1, '__age': 100}
1
{'_A__age': 99, '__age': 100}
(四)私有方法
形如:__方法名,在类外部不能使用
作用:在开发的过程中保护核心代码
class Phone():
def test(self):
print('test1')
def __test1(self):
print('test1')
x=Phone()
x.test()
# 私有方法,无法调用
x.__test1() # 报错
私有方法在类中使用:
class Phone():
def __phone(self):
print('正在拨打电话')
def phone(self,m):
if m >=30:
self.__phone()
else:
print('请先交费30元,再打电话')
x=Phone()
x.phone(36) # 正在拨打电话
二、继承特性
(一)什么是继承
继承就是让类和类之间产生父子关系,子类可以拥有父类的静态属性和方法。
一个类可以继承一个或多个类,父类又可称为基类或超类,新建的类称为派生类或子类。
python中的继承分为:单继承和多继承
(二)继承的作用
提高代码的重用率
class Animal():
def __init__(self,name,age,sex):
self.name=name
self.age=age
self.sex=sex
def jiao(self):
print(self.name+'叫')
def eat(self):
print(self.name+'吃')
class Cat(Animal):
def climb(self):
print(self.name+'爬树')
class Dog(Animal):
def swimming(self):
print(self.name+'游泳')
d=Dog('藏獒',7,'公')
d.eat()
d.jiao()
d.swimming()
c=Cat('波斯猫',4,'母')
c.eat()
c.jiao()
c.climb()
(三)查看继承的父类
print(Cat.__bases__) # (<class '__main__.Animal'>,)
print(Animal.__bases__) # (<class 'object'>,)
(四)方法的覆写
子类中定义了和父类中相同的方法,我们叫做方法的复写(派生方法)。
class A():
def hehe(self):
print('A:呵呵')
class B(A):
def hehe(self):
print('B:呵呵')
a=A()
b=B()
a.hehe() # A:呵呵
b.hehe() # B:呵呵
(五)super()
子类和父类中有相同的方法,如果子类想调用父类的相同方法,可以使用super()方法。
class Animal():
def __init__(self,name,age):
self.name=name
self.age=age
class Cat(Animal):
def __init__(self,name,age,velocity):
self.v=velocity
super().__init__(name,age)
def jiao(self):
print('喵喵喵,速度{}'.format(self.v))
class Dog(Animal):
def jiao(self):
print('汪汪汪')
c=Cat('波斯',3,200)
d=Dog('京巴',4)
c.jiao()
d.jiao()
super()还可以从外部使用,需要传递类名(本类)和对象名
class A():
num=3
__num1=2
def __init__(self,x,y):
self.x=x
self.y=y
class B(A):
num=10
def __init__(self,x,y,z):
self.z=z
super().__init__(x,y)
b=B(1,2,3)
print(b.x)
print(B.num)
# print(B.__num1) # 报错
print(A.num)
print(super(B,b).num)
三、多继承
(一)多继承注意事项
如果子类与父类又相同的方法,就会调用子类中的方法
class A():
def t(self):
print('A:t1')
class B():
def t(self):
print('B:t2')
class C(A,B):
def t(self):
print('C:t3')
c=C()
c.t()
如果不同的父类存在同样的方法名称,根据MRO方法解析顺序列表进行查找。
class A():
def tx(self):
print('A:t1')
class B():
def tx(self):
print('B:t2')
class C(B,A): # A在前,先A;B在前,先B
def t(self):
print('C:t3')
c=C()
c.tx()
(二)继承原理(钻石继承)
1.子类会先于父类被检查
2.多个父类会根据它们在列表中的顺序被检查
3.如果对下一个类存在两个合法的选择,选择第一个父类
(三)多继承中super的本质--表示mro表的下一个
class A():
def func(self):
print('A开始')
print('A结束')
class B(A):
def func(self):
print('B开始')
super().func()
print('B结束')
class C(A):
def func(self):
print('C开始')
super().func()
print('C结束')
class D(B,C):
def func(self):
print('D开始')
super().func()
print('D结束')
print(D.mro())
d=D()
d.func()
class A():
def __init__(self):
print('A开始')
print('A结束')
class B(A):
def __init__(self):
print('B开始')
super().__init__()
print('B结束')
class C(A):
def __init__(self):
print('C开始')
super().__init__()
print('C结束')
class D(B,C):
def __init__(self):
print('D开始')
super().__init__()
print('D结束')
print(D.mro())
d=D()
class A():
def __init__(self):
print('A')
super().__init__()
class B():
def __init__(self):
print('B')
super().__init__()
class C(A,B):
def __init__(self):
print('C')
super().__init__()
c=C()
print(C.mro())
四、多态
class Dog():
def jiao(self):
print('汪汪')
class Cat():
def jiao(self):
print('喵喵')
class Pig():
def jiao(self):
print('哼哼')
def hehe(a):
a.jiao()
d=Dog()
c=Cat()
p=Pig()
# 若不知道d,c,p对象是什么类型的对象,就不知道会执行哪个
# 这就是多态
hehe(d)
hehe(c)
hehe(p)
class Ali():
def pay(self,money):
print('阿里支付:',money)
class WChat():
def pay(self,money):
print('微信支付:',money)
class Person():
def comsume(self,x,money):
x.pay(money)
a=Ali()
w=WChat()
zs=Person()
zs.comsume(a,100)
zs.comsume(w,200)
五、实例方法、类方法和静态方法
class A():
num=10
def hehe(self):
print('我是实例方法,也叫对象方法')
@classmethod
def haha(cls):
print('我是类方法,我的第一个参数代表的是类,A')
print(cls.num)
@staticmethod
def heihei():
print('我是静态方法,跟这个类没有太多血缘关系')
a=A()
a.hehe()
A.hehe(a) # 用类名访问对象方法,第一个参数如果传过来的是对象,就可以,了解即可,不建议使用
A.haha()
a.haha() # 传进去的参数,虽然是对象,但知道它属于哪个类
A.heihei()
a.heihei()