python 面向对象理解
简介
与java语言一样,python也属于面向对象编程,除此之外,还有面向过程编程、函数式编程。
- 面向过程编程:依据业务逻辑自上而下一步一步编写, 可能会存在冗余现象
- 函数式编程:需要编程语言可以将方法或函数作为返回值,python支持函数式编程,但java就不支持,编写函数,然后在使用时调用即可
- 面向对象编程:将函数进行分类、封装,由不同对象进行调用触发,使得代码便于扩展与编写,减少代码重复
什么是面向对象编程呢?
面向对象是一种编程方式,主要通过类
和对象
实现,
类相当于是一个模板,里面提供了很多函数实现功能
对象就是模板中实例化后生成的对象,调用模板中的函数实现相应操作
所以整体的逻辑就是通过类创建对象
->对象
调用类中的方法
面向对象的三大特性
面向对象有三大特性:封装、继承、多态。
封装
将内容封装到一个函数中,提供给对外调用,调用者只需要调用实现相应功能,而无需知道内部实现逻辑。示例如下:
class Person:
def __init__(self, name, age) -> None:
self.name = name
self.age = age
def run(self):
print(f"{self.name} run")
def eat(self):
print(f"{self.name} eat")
def sleep(self):
print(f"{self.name} sleep")
p1 = Person("tom", 19)
p2 = Person("mike", 20)
p1.eat()
p2.eat()
p1.run()
p2.run()
tom eat
mike eat
tom run
mike run
人可以吃饭、睡觉、跑步,将这三个动作分别封装成三个方法,并使用构造方法创建对应的对象,对象直接调用类中的公开方法,当对象实例化后,相当于self变成了对象。
综上,封装就是使用构造方法创建对象后,对象直接或间接使用self调用类中的公开方法进行操作(获取封装的内容)。
继承
面向对象中的继承与实际生活中的继承是类似的,子类可以继承父类,并使用父类中的属性或者方法,示例如下:
class Animal:
def __init__(self, name) -> None:
self.name = name
def run(self):
print(f"{self.name} run")
def eat(self):
print(f"{self.name} eat")
def sleep(self):
print(f"{self.name} sleep")
class Person(Animal):
def __init__(self, name, age) -> None:
super().__init__(name)
self.age = age
def read(self):
print(f"{self.name} read: age:{self.age}")
p1 = Person("tom", 19)
p2 = Person("mike", 20)
p1.eat()
p2.eat()
p1.run()
p2.run()
p1.read()
p2.read()
tom eat
mike eat
tom run
mike run
tom read: age:19
mike read: age:20
每种动物都有吃饭、睡觉、跑步,可以将此类具有这三个行为的事物提取成一个公共的类,然后Person直接继承动物类,这样Person也可以调用动物类中的方法,也可以实现新的方法,避免了代码的冗余。
综上,继承就是将多个相同属性或者动作的对象的行为提取到一个公共类中,不同对象可以继承公共类而不需要实现每一个方法,并且可以实现新的方法。
那么既然有继承,涉及到多重继承和多继承。
多重继承
多重继承:子类继承父类,父类继承父类的父类,以此类推,子->父->爷
大部分编程语言都支持多重继承,此处以python为例:
class Animal:
def __init__(self, name) -> None:
self.name = name
def run(self):
print(f"{self.name} run")
def eat(self):
print(f"{self.name} eat")
def sleep(self):
print(f"{self.name} sleep")
class Person(Animal):
def __init__(self, name, age) -> None:
super().__init__(name)
self.age = age
def read(self):
print(f"{self.name} read: age:{self.age}")
class Child(Person):
def __init__(self, name, age) -> None:
super().__init__(name, age)
def climb(self):
print(f"{self.name}: climb")
p1 = Child("tom", 2)
p2 = Child("mike", 4)
p1.eat()
p2.eat()
p1.run()
p2.run()
p1.climb()
p2.climb()
tom eat
mike eat
tom run
mike run
tom: climb
mike: climb
上述,小孩继承人类,人类继承动物,形成了多重继承,自上而下的一层一层的,下一层级可以调用上一级的方法,即子类可以调用父类的属性或方法,父类不可以调用子类的属性或方法。
多重继承一般适用于存在多重类别的区分的情况,很多模块的源码中就是使用的多重继承。
多继承
顾名思义:多继承就是一个子类可以有多个父类。
python支持多继承,java、c等不支持多继承,示例如下
class Animal:
def __init__(self, name) -> None:
self.name = name
def run(self):
print(f"Animal {self.name} run")
def eat(self):
print(f"Animal {self.name} eat")
def sleep(self):
print(f"Animal {self.name} sleep")
class Person:
def __init__(self, name) -> None:
self.name = name
def run(self):
print(f"Person {self.name} run")
def eat(self):
print(f"Person {self.name} eat")
def sleep(self):
print(f"Person {self.name} sleep")
def thinking(self):
print(f"Person {self.name} thinking")
class Child(Person, Animal):
def __init__(self, name) -> None:
super().__init__(name)
def climb(self):
print(f"{self.name}: climb")
p1 = Child("tom")
p2 = Child("mike")
p1.eat()
p2.eat()
p1.run()
p2.run()
p1.climb()
p2.climb()
p1.thinking()
p2.thinking()
Person tom eat
Person mike eat
Person tom run
Person mike run
tom: climb
mike: climb
Person tom thinking
Person mike thinking
小孩继承了Person,也继承了Animal,但是在调用父类相同方法时,调用了Person的方法,调用父类不存在的方法时,则调用子类自己的方法。
多继承过程中,子类在调用父类中同名的方法时,会按照继承的先后顺序来调用,从前到后依次查找直至找到为止。
继承过程中的深度优先与广度优先
在python2
中, 继承中的深度优先与广度优先一般出现在不同的类创建方式中,分别为经典类和新式类。
经典类
本类和父类未继承object类实现的类。
class D:
def run(self):
print("D.run")
class C(D):
def run(self):
print("C.run")
class B(D):
def run3(self):
print("B.run")
class A(B, C):
def run2(self):
print("A.run")
A().run()
python2
D.run
python3
C.run
新式类
本类或父类继承object类的类
class D(object):
def run(self):
print("D.run")
class C(D):
def run(self):
print("C.run")
class B(D):
def run3(self):
print("B.run")
class A(B, C):
def run2(self):
print("A.run")
A().run()
python2、python3
C.run
由上述结果可得出以下结论:
- 在python2中,经典类调用run方法时,查找顺序为A -> B -> D -> C,属于深度优先,新式类调用run方法时,查找顺序为A -> B -> C -> D,属于广度优先。
- 在python3中,无论是经典类还是新式类,都是广度优先
继承过程中,子类如何调用父类的方法或者属性呢?
使用super()来调用父类的方法
多态
python 不支持多态,也不用支持多态,崇尚鸭子类型
鸭子类型
在python中,有这么一个类型,一只鸟长的像鸭子,会游泳,就叫它鸭子,即鸭子类型。此类型的目的在于关于对象的使用(如何调用),而非关注对象的类型
总结
面向对象编程就是将对象中的共性提取成一个个方法或者属性,方便对象调用,减少了代码的冗余,提升了模块化能力,方便扩展。