面向对象编程(Object-Oriented Programming)
OOP编程是利用“类”和“对象”来创建各种模型来实现对真实世界的描述,使用面向对象编程的原因一方面是因为它可以使程序的维护和扩展变得更简单,并且可以大大提高程序开发效率 ,另外,基于面向对象的程序可以使它人更加容易理解你的代码逻辑,从而使团队开发变得更从容
class Foo: # 定义一个类,class(关键字)
def __init__(self, name): # 初始化方法(构造方法)
self.name = name # self 是对象自己
def say_hello(self): # 普通方法
print(f'hello:{self.name}')
obj = Foo('Otis') # 实例化一个对象
obj.say_hello() # 调用普通方法
我们并没有调用init(self,…)
,但它会自动执行,因为它叫初始化方法(构造方法),就是在实例化完成的时候,用来初始化一些数据的,比如初始化你实例的名字、年龄等属性
面向对象的三大特征
- 封装
- 继承
- 多态
一、封装
封装,顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容。
class Foo:
def __init__(self, name, age):
self.name = name
self.age = age
def info(self):
print(f'你的名字是{self.name},年龄是{self.age}')
obj = Foo('Otis', 20) # 将 Otis 和 20 封装到 obj 对象中
print(obj.name) # 通过对象直接调用
print(obj.age)
obj.info() # 通过类中的方法调用
# 当对象调用类中的普通方法时,Python自动会将当前对象传递给该方法
# 即 info 当中的 self 就是 obj
封装的优点
- 良好的封装能够减少耦合
- 类内部的结构可以自由修改
- 可以对成员变量进行更精确的控制
- 隐藏信息,实现细节
封装原则
- 将不需要对外提供的内容都隐藏起来
- 把属性都隐藏,提供公共方法访问
私有变量和私有方法
class A:
# 类的数据属性就应该是共享的,但是语法上是可以把类的数据属性设置成私有的如__N,会变形为_A__N
__N = 0
def __init__(self):
self.__X = 10 # 变形为self._A__X
def __foo(self): # 变形为_A__foo
print('from A')
def bar(self):
self.__foo() # 只有在类内部才可以通过__foo的形式访问到.
# A._A__N是可以访问到的,即这种操作并不是严格意义上的限制外部访问,仅仅只是一种语法意义上的变形
-
类中定义的x只能在内部使用,如self.__x,外部引用的就是变形的结果
-
这种变形其实正是针对外部的变形,在外部是无法通过__x这个名字访问到的
-
这种机制也并没有真正意义上限制我们从外部直接访问属性,知道了类名和属性名就可以拼出名字:类名_属性,然后就可以访问了,如a._A__N
-
变形的过程只在类的内部生效,在实例化后再定义的赋值操作,不会变形
二、继承
继承,面向对象中的继承和现实生活中的继承相同,即:子可以继承父的内容。
例如:
- 猫:吃,喝,叫
- 狗:吃,喝,叫
正常情况,要分别为2类动物创建一个类,并实现他们的吃,喝,叫功能
使用继承可以将类共有的方法提取出来(父类),只要子类继承父类就能拥有父类的方法
class Animal:
def eat(self):
print(f'{self} 在吃东西')
def drink(self):
print(f'{self} 在喝东西')
class Cat(Animal):
def __init__(self, name):
self.name = name
self.species = '猫'
def say(self):
print('喵喵喵')
class Dog(Animal):
def __init__(self, name):
self.name = name
self.species = '狗'
def say(self):
print('汪汪汪')
cat1 = Cat('小咪')
dog1 = Dog('旺财')
cat1.say()
dog1.eat()
多继承
Python的类如果继承了多个类,那么其寻找方法的方式有两种,分别是:深度优先和C3算法(广度优先)
- 当类是经典类时,多继承情况下,会按照深度优先方式查找
- 当类是新式类时,多继承情况下,会按照广度优先方式查找
在python2中当前类或父类没有继承object类就是经典类,否则否则就是新式类
在python3中不管有没有继承object类都是新式类
经典类多继承
class D:
def bar(self):
print 'D.bar'
class C(D):
def bar(self):
print 'C.bar'
class B(D):
def bar(self):
print 'B.bar'
class A(B, C):
def bar(self):
print 'A.bar'
a = A()
# 执行bar方法时
# 首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去D类中找,如果D类中么有,则继续去C类中找,如果还是未找到,则报错
# 所以,查找顺序:A --> B --> D --> C
# 在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了
a.bar()
新式类多继承
class D(object):
def bar(self):
print 'D.bar'
class C(D):
def bar(self):
print 'C.bar'
class B(D):
def bar(self):
print 'B.bar'
class A(B, C):
def bar(self):
print 'A.bar'
a = A()
# 执行bar方法时
# 首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去C类中找,如果C类中么有,则继续去D类中找,如果还是未找到,则报错
# 所以,查找顺序:A --> B --> C --> D
# 在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了
a.bar()
三、多态
class A:
def func(self):
pass
class B(A):
def func(self):
print('B')
class C(A):
def func(self):
print('C')
def func(obj: A):
obj.func()
b = B()
c = C()
func(b)
func(c)