封装
隐藏内部细节,对外提供操作方式
权限控制:是通过对属性或方法添加单下划线、双下划线以及首尾双下划线来实现
- 单下划线开头:以单下划线开头的属性或方法表示protected受保护的实例属性,这类实例属性被视为仅供内部使用,允许类本身和子类进行访问,但实际上它可以被外部代码访问。
- 双下划线开头:表示private私有的实例属性,这类实例属性只允许定义该属性或方法的类本身进行访问。
- 首尾双下划线:一般表示特殊的方法。
class Student():
#首尾双下划线
def __init__(self,name,age,gender):
self._name = name# self._name受保护的实例属性,只能本类和子类访问
self.__age = age#self.__age表示私有的实例属性,只能类本身去访问
self.gender = gender#普通的实例属性,类的内部、外部、子类都可以访问
def _fun1(self):
print('子类及本身可以访问')
def __fun2(self):
print('只有定义的类可以访问')
def show(self):
self._fun1()#受保护的方法
self.__fun2()#私有的方法
print(self._name)#受保护的实例属性
print(self.__age)#私有的实例属性
stu=Student('张三',20,'男')
print(stu._name)#在类外可以访问受保护的实例属性
#print(stu.__age)#AttributeError: 'Student' object has no attribute '__age'.
stu._fun1()#在类外可以访问受保护的方法
# stu.__fun2()#AttributeError: 'Student' object has no attribute '__fun2'.
在类外访问私有实例属性和方法需要在使用前加 _类名,但是不建议使用
print(stu._Student__age)
stu._Student__fun2()
可以使用修饰器 @property(设置方法,将其转换成属性)来访问私有属性,仅查看,不能修改
class Student:
def __init__(self,name,gender):
self.name = name
self.__gender = gender #self.__gender是私有的实例属性
#使用@property 修改方法
@property
def gender(self):
return self.__gender
stu=Student('X','女')
print(stu.name,'的性别是',stu.gender)
要再加 @已经设置的方法名.setter 再命名一个方法名相同,变量不同的方法(方法重载??)
class Student:
def __init__(self,name,gender):
self.name = name
self.__gender = gender #self.__gender是私有的实例属性
#使用@property 修改方法
@property#使用@property 设置方法,将其转换成属性
def gender(self):
return self.__gender
@gender.setter#这样写才能修改属性
def gender(self,valye):
self.__gender = valye
stu=Student('X','女')
stu.gender='男'#把女修改成男
print(stu.name,'的性别是',stu.gender)
继承
- 在Python中一个子类可以继承N个父类
- 一个父类也可以继承多个子类
- 如果一个类没有继承任何类,那么这个类默认继承object类
继承的语法结构:
class 类名(父类1,父类2,...,父类N):
pass
举例:
class FatherA:#创建父类A
def __init__(self,name):#初始化方法
self.name=name#实例属性赋值
def showA(self):
print('父类A的方法')
class FatherB:#创建父类B
def __init__(self,age):#初始化方法
self.age=age#实例属性赋值
def showB(self):
print('父类B的方法')
class Son(FatherA,FatherB):#子类Son继承两个父类A、B
def __init__(self,name,age,genter):#初始化方法,其中包含两个父类中的变量name、age,还有自己的genter
FatherA.__init__(self,name)#使用父类A的初始化方法
FatherB.__init__(self,age)#
self.genter=genter
def showS(self):
print(f'我是{self.name},今年{self.age},是{self.genter}生')
son=Son('XX',18,'男')
son.showA()
son.showB()
son.showS()
方法重写
- 子类继承了父类就拥有了父类中公有成员和受保护的成员
- 父类的方法并不能完全适应子类的需求,这时候子类就可以重写父类的方法
- 子类在重写父类的方法时,要求方法名称必须与父类的名称相同,在子类重写后的方法中可以通过super().xxx()调用父类中的方法
class Father:#创建父类
def __init__(self,name,age):#初始化方法
self.name=name#实例属性赋值
self.age=age
def show(self):
print(f'我是{self.name},今年{self.age}')
class Son(Father):
def __init__(self,name,age,stuNo):
super().__init__(name,age)
self.stuno=stuNo
def show(self):#重写父类的 show 方法
super().show()#输出一遍父类
print(f'学号是:{self.stuno}')
son=Son('XXX',21,'1001')
son.show()
class Doctor(Father):
def __init__(self,name,age,room):
super().__init__(name,age)
self.room=room
def show(self):
print(f'我叫{self.name},今年{self.age},在{self.room}办公')
doctor=Doctor('YYY',30,1002)
doctor.show()
多态
- 指的就是“多种形态”,即便不知道一个变量所引用的对象到底是什么类型,仍可以通过这个变量调用对象的方法。
- 在程序运行过程中根据变量所引用对象的数据类型,动态决定调用哪个对象中的方法。
- Python语言中的堕胎,根本不关心对象的数据类型,也不关心类之间是否存在继承关系,只关心对象的行为(方法)。只要不同的类中有同名的方法,即可实现多态。
class Person:
def eat(self):
print('人吃五谷杂粮')
class Cat:
def eat(self):
print('猫吃鱼')
class Dog:
def eat(self):
print('狗吃骨头')
#这三个类中都有一个同名的方法 eat
#编写函数
def fun(obj):#obj是函数的形式参数,在定义处不知道形参的类型
obj.eat()
#创建三个类的对象
per=Person()
cat=Cat()
dog=Dog()
#调用fun
fun(per)#Python中的多态,不关心对象的数据类型,只关心对象是否具有同名方法
fun(cat)
fun(dog)
有点抽象....
调试打上断点
先到 fun
obj数据类型为Person
然后输出了Person的函数eat()
下一步obj数据类型变成了Cat,然后输出.....
接下来也一样。
应该能理解为:
把类当参数传递,一般传递的是变量。有点像委托。
函数传递对象