面向对象

打印 上一主题 下一主题

主题 986|帖子 986|积分 2958

1.什么是面向对象和面向过程编程思想

面向过程:
1.核心是‘过程’二字
2.过程的含义是将程序流程化
3.过程是流水线,用来分步骤解决问题的
面向对象:
1.核心是‘对象’二字
2.对象的含义是将程序进行整合
3.对象是‘容器’,用来盛放数据和功能(变量和函数)
总结:以做西红柿鸡蛋面为例:
面向过程:我需要买西红柿--》买鸡蛋、面--》把西红柿洗好、鸡蛋打好...等等
面向对象:找个人帮我干活,我只需要告诉那个人我需要吃西红柿鸡蛋面(调用该对象),具体的过程交给别人干。

python中可以用来盛放数据和功能的‘容器’可以是字典、列表、集合等。但是这些容器在存放功能的时候,并不能把功能的具体代码全部传进去(只能传一个函数名),这就有一定的局限性!
那么。python中提供了什么样的语法来让我们更好的存放数据和功能呢??
2.类

类,其实也是‘容器’,它是用来存放对象1、对象2、对象3...等共有的数据和功能!
它能够更好的节省空间并且帮我们更好完成面向对象的编程!
2.1 类的引入
  1. # 所有类体中最常见的就是变量和功能的定义,但是类体中也可以包含其他代码
  2. # 注意:类体中的代码是在定义阶段就会执行的,也就是说在定义阶段就开辟了名称空间
  3. class ClassName: # 类的定义 class 类名:
  4.     # 变量(数据)的定义
  5.     var = 111
  6.     # 功能的定义
  7.     def send(self):
  8.         pass
  9.     def rcv(self):
  10.         pass
  11.                
  12. # 类中提供了一个方法查看类的名称空间.__dict__,得到一个字典
  13. print(ClassName.__dict__)
  14. # __dict__[key]调用类体中的变量值或者功能
  15. print(ClassName.__dict__['send'])
  16. # 为了简便上述的调用方式,类提供了.变量/.函数名的方法来调用,注意不加括号
  17. print(ClassName.send)
复制代码
2.2 类的调用--产生对象
  1. # 类的调用,类名()的方式返回了一个class_obj对象,就是把类和该对象建立了一个联系,该对象就可以使用类里面的定义的变量和功能了
  2. class_obj = ClassName()
  3. # 该对象的.__dict__方法得到的是一个空字典,可以使用对象.属性名=属性值的方式给该字典添加值
  4. print(class_obj.__dict__)
  5. # 类名.变量名/类名.函数名 调用类的变量和功能
  6. print(class_obj.var)
复制代码
2.3 类的__init__方法

当对象1、对象2、对象3...等的属性都一样,只是值不同的时候,我们不断的使用对象.属性=属性值给对象赋值的时候,不免需要个每个对象都这样操作,这样会使得代码冗余。
因此类中有一个 __init__的初始化方法,会自动帮你封装好这个对象独有的属性,你只需要在调用的时候传入对应的属性值就行。
  1. class ClassName:
  2.     # 参数self表示调用类时产生的对象,x和y是调用类时对应传人的参数
  3.     def __init__(self,x,y):
  4.         self.name = x
  5.         self.age = y
  6. # 调用类产生对象的操作,实际上是类的实例化的过程,这个过程发生了三件事
  7. # 1.产生了一个空对象
  8. # 2.自动调用类里面的__init__方法,并将调用时候的参数对应传给__init__方法
  9. # 3.返回初始化好的对象class_obj
  10. class_obj = ClassName('zhang',18)
复制代码
总结:
1.该方法会在调用类的时候自动执行,用来为对象初始化自己独有的属性
2.该方法内存放的是为对象初始化属性的功能,但是也可以存放其他需要在调用时就执行的代码
3.该方法的返回值只能是none

2.4 类中的属性查找

1.数据属性
类中属性查找的顺序是对象先从自己那查找,如果找不到该属性,则去类里面查找。对象修改添加属性和属性值,这并不会影响类里面对应的属性,其余对象获取到的还是原来类里面定义的属性值
类中定义了对象所需要的所有的共有属性和功能,大家访问共有属性和功能的地址都是一样的。

2.函数属性
正在调用类中的方法是需要按照:类名.函数名(对象)的方法进行调用,但是这样未免太过麻烦。
所以,类提供了一种绑定方法:对象在调用类中功能(函数)时,会自动把该对象当成参数自动传入。
对象1.类中函数名()==类名.函数名(对象) #这里默认函数名传入了对象1
回顾一下列表、字典,其实也是采用了类的思想!
l=[11,22,33] 等价于 l=list([11,22,33])
其实list就是一个类,l就是一个对象
l.append('dd')等价于list.append(l,'dd') 就是调用list类里的append方法
2.5 类中如何隐藏属性

在属性名前加__前缀,就会实现一个隐藏的效果,外界就不能调用该属性了。
该方法只是语法形式上的变形,通过__dict__查看其真正的语法名,然后在外部也是可以访问到的!
隐藏属性在外部访问不到,但是在类内部还是可以访问到的
这样操作的目的是:不让外部轻易的访问到内部的属性,即使需要访问,也必须需要一些条件。

2.6 类中的property

property其实就是一种装饰器,它的功能是把类中的方法伪装成数据属性,调用的时候就不用调用该方法了,直接把方法当成数据调用即可(不用加括号了)。
  1. class ClassName:
  2.     def __init__(self):
  3.         self.__name = name
  4.     @property #法一:
  5.     def get(self):
  6.         return __self.name
  7.     def set(self,val):
  8.         self.__name = val
  9.     # 法二:伪装的更像了
  10.     name = property(get,set)
  11.     # 改进:直接在函数上加@name.setter(修改值装饰器)@name.deleter(删除值装饰器),把函数名都改成name
  12. class_obj = ClassName()
  13. # 法一调用,不用加括号了
  14. class_obj.get
  15. # 法二调用
  16. class_obj.name #获取名字
  17. class_obj.name=123 #修改名字
复制代码
2.7 类中classmethod方法

在类中,我们定义的方法默认是绑定给对象的,即在实例化类的时候,对象会默认当成参数传入到类中的方法里面。
obj = ClassName() #这里obj自动传入了
如何定义一个方法,该方法是默认传入类的呢??

只需要在我们需要绑定的方法前面加上@classmethod就行,下次我们在调用该类的方法时会自动传入该类名,调用者是类。
  1. class B:
  2.     @classmethod
  3.     def fun(cls):
  4.         pass
复制代码
2.8 staticmethod方法

不需要绑定给类或者对象的方法,在对应函数上加上@staticmethod,调用者可以是类或者对象,没有自动传参的效果。
3. 面向对象的三大特性

3.1 封装

封装其实就是整合,对于共有的数据和功能进行整合。
3.2 继承

3.2.1 什么是继承

继承是一种创建新类的方式,新建的类可以称为子类或者派生类,继承的类可以称为父类或者基类
python支持多继承,就是一个新建的类可以继承多个父类,python3默认继承object类,在python2中继承了object的叫新式类,没有继承的叫经典类,python2中需要手动书写需要继承的类,不会默认继承object。
  1. class Student(object):
  2.     pass
  3. class Student2(object):
  4.     pass
  5. class Sub(Student):# 父类是Student
  6.     pass
  7. class Sub2(Student,Student2): # 父类是Student和Student2
  8.     pass
复制代码
3.2.2 为什么要用继承

类是用来对象数据和功能冗余的问题,而类是用来解决类与类的冗余
3.2.3 继承中的菱形问题的属性查找(后砖石问题)

菱形问题实际指的是,在python2和python3中菱形模式的继承会导致,继承查找顺序不一致的问题!!,这个需要注意!

D类继承了B和C类,B和C类分别继承了A类,如果A中有一个方法,B和C都重写了该方法,而D没有重写,那么D继承的是哪个版本的方法呢?
  1. class A:
  2.     def test(self):
  3.         print('from A')
  4. class B(A):
  5.     def test(self):
  6.         print('from B')
  7. class C(A):
  8.     def test(self):
  9.         print('from C')
  10. class D(B,C):
  11.     pass
  12. obj = D()
  13. obj.test()
  14. # 查找会从D-->B-->C-->A,如果D的父类顺序换了,则查找顺序也会变成D-->C-->B-->A,python2中的经典类就不一样了,查找顺序为D-->B-->A-->C
复制代码
其实,对于你定义的每一个类,python都会计算出一个方法解析顺序(MRO)列表,该MRO列表就是一个简单的所有基类的线性顺序列表。
对象.mro()或者类.mro()  #查看MRO线性顺序列表
python会在MRO列表中从左到右开始查找基类,知道找到第一个匹配这个属性的类为止,这个MRO列表的构造是通过一个C3线性化算法来实现的(了解一下即可)。
3.2.4 非菱形问题下的查找顺序


python2和3的查找顺序为:A-->B--->E--->C--->F--->D---object
3.2.5 多继承下的mixins机制

mixins机制的核心:就是在多继承的背景下尽可能的提升多继承的可读性
python的多继承类中,应当只有一个标识其归属含义的父类,意思是保证多继承的类遵循继承‘is-a’的原则,其余继承的类都应该是mixin类,该类的命名规范一般是以mixin、able、ible为后缀。
mixin类只是用来表达某一类功能的类,并不决定子类的归属,它也不依赖于子类的实现,而且子类也并不是完全依赖mixin类,缺少了该类,子类照常工作,只是缺少了某种功能罢了!!

最后,mixin类尽量少用,当mixin类很多的时候,依然会造成可读性差的问题!!
3.2.6 子类派生的新方法中如何重用父类功能

法一:指名道姓的调用某一个类下面的函数,该方法不依赖类的继承
  1. class A:
  2.     def __init__(self,name,age):
  3.         self.name = name
  4.         self.age = age
  5. class B:
  6.     def __init__(self,name,age,work):
  7.         A.__init__(self,name,age) # 法一:指名道姓
  8.         self.work = work
  9. obj = B('zhang','18','python')
  10. print(obj.__dict__)
复制代码
法二:super()方法,该方法严格依赖继承关系
  1. 调用super()会得到一个特殊的对象,注意该对象是参照当前发起属性查找那个类的mro,去当前类的父类中查找属性!! 辅助下面的列子进行理解!
  2. class A:
  3.     def test(self):
  4.         print('from A')
  5.         super(A, self).test() # python3中super也可以省略括号里的参数
  6. class B:
  7.     def test(self):
  8.         print('from B')
  9. class C(A,B):
  10.     pass
  11. obj = C()
  12. obj.test()
  13. # 1.首先会到obj对象里面去找test方法
  14. # 2.再去C里面找
  15. # 3.再去A里面找test方法,找到了打印
  16. # 4.然后遇到了super()会得到一个特殊的对象,该对象参照当前发起属性查找的类的mro就是C这个类,去当前调用super()方法的父类中查找test属性
  17. # 5.C这个类的mro是[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
  18. # 6.当前super()方法的父类是B
  19. print(C.mro())
复制代码
3.3 多态与鸭子类型

多态性和鸭子类型的本质在于,不同的类中定义了相同的方法名,这样我们就可以不考虑类而统一用一种方式去使用对象。
比如,所有的类中都定义了read和write方法,那么我们在调用的时候就可以不考虑类,直接让类实例化出来的对象调用read和write方法就行。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

笑看天下无敌手

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表