概括
Python中面向对象编程有三大特性:封装、继承和多态。
封装: 函数是对语句的封装;类是对函数和变量的封装。
继承: 类和类之间可以人为手动的建立父子关系,父类的属性和方法,子类可以使用。
多态: 是一种编程技巧,提高代码的灵活度。
1.封装
函数是对一个一个语句进行封装。
def test():
x = 18 # 赋值语句
x += 2 # 算数运算符表达式语句
print('hello world')
类是对函数和变量的封装
class Person(object):
type = '人类'
def __init__(self):
pass
def play_game(self):
pass
2.继承
继承是面向对象软件设计中的一个概念,描述的是多个类之间的所属关系,可以使子类具有分类的属性和方法,或者重新定义,追加属性和方法等。
例如一个A类的属性和方法可以复用,B类继承于A类,那么A类可称为基类,亦可叫做父类,B类则被称为派生类,亦可叫做子类。
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
def sleep(self):
print(self.name + '正在睡觉')
class Student(Person):
def study(self):
print(self.name + '正在看书')
# 调用 __init__ 方法,Student类没有实现,会自动找 Person 父类
s1 = Student('张三', 18)
print(s1.name) #张三 父类里定义的属性,子类可以直接使用
s1.sleep() #张三正在睡觉 父类的方法子类实例对象可以直接调用
s1.study() #张三正在看书
多继承
子类可以有多个父类,继承所有父类的属性和方法。
语法格式:
class 子类名(父类名1,父类名2...)
pass
class A(object):
def test1(self):
print('我是test1')
def demo(self):
print('我是A类里的demo方法')
class B(object):
def test2(self):
print('我是test2')
def demo(self):
print('我是B类里的demo方法')
class C(A, B):
pass
c = C()
c.test1()
c.test2()
# 如果两个不同的父类有同名方法,可以使用__mro__属性可以查看方法的调用顺序
c.demo()
print(C.__mro__)
运行结果:
我是test1
我是test2
我是A类里的demo方法
(<class ‘main.C’>, <class ‘main.A’>, <class ‘main.B’>, <class ‘object’>)
私有属性的继承特点
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
self.__score = 90
def sleep(self):
print(self.name + '正在睡觉')
def __test(self):
print('我是Person类里的test方法')
class Student(Person):
def __demo(self):
print('我是Student里的demo方法')
p = Student('源', 18)
print(p.name)
p.sleep()
p._Student__demo() # 自己类里定义的私有方法 对象名._类名__私有方法名()
p._Person__test() # 可以通过 对象名._父类名__私有方法调用()
print(p._Person__score)
运行结果:
源
源正在睡觉
我是Student里的demo方法
我是Person类里的test方法
90
私有属性和方法,子类不会继承
所以 p._Student__test() ,print(p._Student__score),会报错。
新式类与经典类
新式类:继承自object的类,我们称之为新式类
经典类:不继承自object的类
在python2里,如果不手动的指定一个类的父类是object,这个类就是一个经典类
在python3里不存在经典类,都是新式类。
使用dir函数可以查看object类提供的一些内置属性和方法。
class Student:
pass
s = Student()
print(dir(s))
对象相关的运算符和内置函数
身份运算符用来比较两个对象的内存地址,查看这两个对象是否是同一个对象。
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
class Teacher(object):
pass
class Student(Person, Teacher):
pass
p1 = Person('源', 18)
p2 = Person('源', 18)
print(p1 is p2) # False,两个对象的内存地址不一样
type内置函数用来获取类对象
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
class Teacher(object):
pass
class Student(Person, Teacher):
pass
p1 = Person('源', 18)
s = Student('张三', 20)
print(type(p1) == Person) # True
print(type(s) == Person) # False
isinstance内置函数用来判断一个对象是否是由指定的类(或者父类)实例化出来的
print(isinstance(s, (Student, Teacher))) # True
print(isinstance(s, Person)) # True
print(isinstance(p1, Person)) # True
print(isinstance(p1, Student)) # False
issubclass 内置函数用来判断一个类是否是另一个类的子
print(issubclass(Student, (Person, Teacher))) # True
print(issubclass(Person, Student)) # False
子类重写父类方法
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
def eat(self):
print(self.name + '正在吃东西')
class Student(Person):
def __init__(self, name, age, score):
# 子类在父类实现的基础上,又添加了自己新的功能
# 调用父类方法的两种方式:
# 1. 父类名.方法名(self,参数列表)
# Person.__init__(self, name, age)
# 2. 使用super直接调用父类的方法。推荐使用第二种方式
super(Student, self).__init__(name, age)
self.score = score
def eat(self):
print(self.name + '在课间休息时吃东西')
s = Student('源', 18, 90) # 调用了父类的 __init__ 方法
s.eat()
print(Student.__mro__)
运行结果:
源在课间休息时吃东西
(<class ‘main.Student’>, <class ‘main.Person’>, <class ‘object’>)
1.子类的实现和父类的实现完全不一样,子类可以选择重写父类的方法。
2.子类在父类的基础上又有更多的实现
3.多态
多态是基于继承,通过子类重写父类的方法,达到不同的子类对象调用相同的父类方法,得到不同的结果,提高代码的灵活度。
不使用多态时:
class PoliceDog(object):
def attack_enemy(self):
print('警犬正在攻击坏人')
class BlindDog(object):
def lead_road(self):
print('导盲犬正在领路')
class DrugDog(object):
def search_drug(self):
print('缉毒犬正在搜毒')
class Person(object):
def __init__(self, name):
self.name = name
self.dog = None
def work_with_pd(self):
if self.dog is not None:
self.dog.attack_enemy()
def work_with_bd(self):
if self.dog is not None:
self.dog.lead_road()
def work_with_dd(self):
if self.dog is not None:
self.dog.search_drug()
p = Person('源')
pd = PoliceDog()
p.dog = pd
p.work_with_pd()
bd = BlindDog()
p.dog = bd
p.work_with_bd()
dd = DrugDog()
p.dog = dd
p.work_with_dd()
不使用多态时,若不断添加新的功能,每次都需要改动Person类的源码,使得程序的扩展性太差。
使用多态时:
class Dog(object):
def work(self): # 父类提供统一的方法。
print('狗正在工作')
class PoliceDog(Dog): # 继承Dog
def work(self): # 子类重写方法,并且处理自己的行为
print('警犬正在攻击敌人')
class BlindDog(Dog):
def work(self):
print('导盲犬正在领路')
class DrugDog(Dog):
def work(self):
print('缉毒犬正在搜毒')
class Person(object):
def __init__(self, name):
self.name = name
self.dog = None
def work_with_dog(self):
if self.dog is not None and isinstance(self.dog, Dog):
self.dog.work() # 根据对象的不同而产生不同的运行效果, 保障了代码的稳定性
p = Person('源')
pd = PoliceDog()
p.dog = pd
p.work_with_dog()
bd = BlindDog()
p.dog = bd
p.work_with_dog()
dd = DrugDog()
p.dog = dd
p.work_with_dog()
运行结果:
警犬正在攻击坏人
导盲犬正在领路
缉毒犬正在搜毒
使用多态时,同一个方法,只要是 Dog 的子类就可以传递,提供了代码的灵活性,并且传递不同对象,最终 work_with_dog 产生了不同的执行效果。