目录
一、封装
1、私有变量
2、私有方法
3、使用属性
二、继承
2.1单继承:
2.2多继承
2.4方法的重写
三、多态
3.1 继承与多态
3.2 鸭子类型测试与多态
封装性是面向对象重要的基本特性之一。封装隐藏了对象的内部细节,只保留有限的对外接口,外部调用者不用关心对象的内部细节,使得操作对象变得简单。
例如:一台计算机内部及其复杂,有主板,CPU,硬盘,内存等,而一般人不需要了解它的内部细节。计算机制造商用机箱把计算机封装起来,对外提供了一些接口,如鼠标,键盘,和显示器等,使用计算机就变得非常简单了。
为了防止外部调用者随意存取类的内部数据(成员变量),内部数据(成员变量)会被封装成为“私有变量”,外部调用者只能通过方法调用私有变量。
默认情况下,Python中的变量是公有的,可以在类的外部访问它们。如果想让它们成为私有变量,则在变量前加上双下划线(__)即可。
示例:
class Student(object):
def __init__(self, name, age):
self.name = name # 创建并初始化公有实例变量
self.__age = age # 创建并初始化私有实例变量
def print_info(self):
print(f'姓名:{self.name},年龄:{self.__age}')
student1 = Student("samual", 21)
student1.print_info() # 打印名字和年龄出来
print(student1.name) # 打印名字出来
print(student1.__age) # 报错
私有变量可以在类的内部进行访问,不能在类的外部进行访问
私有方法与私有变量的封装是类似的,在方法前面加上双下划线(__)就是私有方法了。
示例:
class Student(object):
def __init__(self, name, age):
self.name = name # 创建并初始化公有实例变量
self.__age = age # 创建并初始化私有实例变量
def __print_info_inner(self): # 定义为私有方法
print(f'姓名:{self.name},年龄:{self.__age}')
def print_info_out(self):
self.__print_info_inner() # 在类的内部调用私有方法
student1 = Student("samual", 21)
student1.print_info_out()
student1.__print_info_inner() # 在外部调用私有方法会报错
为了实现对象的封装,在一个类中不应该有公有的成员变量,这些成员变量应该都被设计成为私有的,然后通过公有的set(赋值)和get(取值)方法来访问。
示例:
class Student(object):
def __init__(self, name, age):
self.name = name # 创建并初始化公有实例变量
self.__age = age # 创建并初始化私有实例变量
# 实例方法
def print_info(self):
print(f'姓名:{self.name},年龄:{self.__age}')
# set方法
def set_age(self,age):
self.__age = age
# get方法
def get_age(self):
return self.__age
student1 = Student("samual", 21)
student1.print_info()
# 输出:姓名:samual,年龄:21
student1.set_age(18)
student1.print_info()
# 输出:姓名:samual,年龄:18
在上面的示例中,当外部调用通过两个公有方法访问被封装的私有成员变量,会比较麻烦,所有我们还有一种简单的方法来访问私有变量,那个就是通过@property和@属性名.setter装饰器来完成。
示例:
class Student(object):
def __init__(self, name, age):
self.name = name # 创建并初始化公有实例变量
self.__age = age # 创建并初始化私有实例变量
# 实例方法
def print_info(self):
print(f'姓名:{self.name},年龄:{self.__age}')
@property
def age(self): # 替代get_age(self)方法
return self.__age
@age.setter
def age(self,age): # 替代set_age(self,age)方法
self.__age = age
student1 = Student("samual", 21)
student1.print_info()
student1.age = 18 # 通过属性赋值来修改
student1.print_info()
继承性也是面向对象重要的基本特性之一。
在现实世界中的继承关系无处不在,例如:猫与动物之间的关系:猫是一种特殊动物,具有动物的全部特征和行为,即数据和操作。在面向对象中动物是一般类,被称为“父类”,猫是特殊类,被称为“子类”。特殊类拥有一般类的全部数据和操作,可称子类继承父类。
在Python中声明子类继承父类的语法很简单,定义类时在类的后面使用一对小括号指定它的父类就可以了,在Python中一般类都继承object。
语法格式:
class 父类(object):
pass
class 子类(Master):
pass
示例:
# 定义动物类
class Animal(object):
def __init__(self,name):
self.name = name
def print_info(self):
print(f'动物的名字叫:{self.name}')
# 定义猫类使其继承动物类
class Cat(Animal):
def __init__(self,name,age):
Animal.__init__(self,name) # 调用父类的构造方法
self.age = age
cat = Cat('Tom',3)
cat.print_info() # 父类的方法被子类继承,子类对象可调用
在调用父类的构造方法时,我们还有一种写法,那就是使用super()函数
super()
函数,它会使子类从其父继承所有方法和属性:
示例:
class Cat(Animal):
def __init__(self,name,age):
super.__init__(name) # 调用父类的构造方法
self.age = age
这种方法与用父类名调用的方法效果是一样的。
一个类继承多个父类
在多继承中 如果多个父类中属性名 或者是方法名相同 那么将按照MRO算法查找
mro:
1.在自己的类中查找 如果找到 就结束
2.在父类元组中按照顺序查找 从左到右
类名.__mro__
所有在Python中,当子类继承多个父类时,如果在多个父类有相同的成员方法和成员变量,则子类优先继续左边父类中的成员方法或成员变量,从左到右继承级别从高到低。
语法格式:
class A(Object):
pass
class B(object):
pass
class C(A,B):
pass
示例:
class Horse(object):
def __init__(self,name):
self.name = name
def show_info(self):
print(f'马的名字叫{self.name}')
def run(self):
print('马跑的很快')
class Donkey(object):
def __init__(self,name):
self.name = name
def show_info(self):
print(f'驴的名字叫{self.name}')
def run(self):
print('驴跑的很慢')
def roll(self):
print('驴打滚')
class Mule(Horse,Donkey):
def __init__(self,name,age):
super().__init__(name)
self.age = age
m = Mule('小骡',2)
m.run() # 继承父类马方法
m.roll() # 继承父类驴方法
m.show_info() # 继承父类马方法
如果子类的方法名与父类的方法名相同,则在这种情况下,子类的方法会重写父类的同名方法。
示例:
class Horse(object):
def __init__(self,name):
self.name = name
def show_info(self):
print(f'马的名字叫{self.name}')
def run(self):
print('马跑的很快')
class Donkey(object):
def __init__(self,name):
self.name = name
def show_info(self):
print(f'驴的名字叫{self.name}')
def run(self):
print('驴跑的很慢')
def roll(self):
print('驴打滚')
class Mule(Horse,Donkey):
def __init__(self,name,age):
super().__init__(name)
self.age = age
def show_info(self):
print(f'骡的名字叫{self.name},今年{self.age}岁')
m = Mule('小骡',2)
m.run() # 继承父类马方法
m.roll() # 继承父类驴方法
m.show_info() # 重写了父类马的方法
多态也是面向对象重要的基本特征之一,“多态”指对象可以表现出多种形态。
例如:猫,狗,鸭子都属于动物,它们有“叫”和“动”等行为,但是它们叫的方式不同,动的方式也不同。
在多个子继承父类,并重写父类方法后,这些子继承所创建的对象之间就是多态的,这些对象采用不同的方式实现父类方法。
示例:
class Animal(object):
def speak(self):
print('动物在叫,但不知道是哪种动物在叫')
class Dog(Animal):
def speak(self):
print('狗:汪汪汪')
class Cat(Animal):
def speak(self):
print('猫:喵喵喵')
an1 = Dog()
an2 = Cat()
an1.speak()
an2.speak()
Python的多态性更加灵活,支持鸭子类型测试。鸭子类型测试:指的是若看到一只鸟走起来像鸭子,游起来像鸭子,叫起来也像鸭子,那么这只鸟就可以被叫作鸭子。
由于支持鸭子类型测试,所有Python解释器不检测发生多态的对象是否继承同一个父类,只要它们有相同的行为(方法),它们之间就是多态的。
例如:我们设计一个函数start(),它接收具有“叫”speak() 方法的对象
class Animal(object):
def speak(self):
print('动物在叫,但不知道是哪种动物在叫')
class Dog(Animal):
def speak(self):
print('狗:汪汪汪')
class Cat(Animal):
def speak(self):
print('猫:喵喵喵')
class Car(object):
def speak(self):
print('汽车:嘀嘀嘀')
def start(obj):
obj.speak()
start(Dog())
start(Cat())
start(Car())
上一章:Python中的面向对象