在实际生活中,当我们遇到一个问题需要解决时,我们会进行一系列的工作来解决问题.
如:当饿了的时候,需要解决这个问题,我们需要做一系列事情:
准备食材;煮饭,炒菜;吃饭.在计算机编程中,利用各种语言解决各种问题.和在实际生活中一样,需要一系列的步骤来编写一个程序.这种编程思想是注重与过程的.所以叫做面向过程编程.
面向对象Object-orientedprogramming在面向过程编程中,解决不同的问题.过程也就不一样,当有两个比较类似的问题时,例如土豆炒肉丝和干扁四季豆这两道菜的做法的步骤虽然不一样,一个直接炒,四季豆需要先煮一下.但是还是有部分的步骤是一样的,虽然顺序不一样.
在计算机编程中类似,很多时候两个程序有很多步骤是差不多的.而面向过程中,当一个程序的写好了后,另一个程序中虽然有些步骤差不多,但是是不能直接调用的,那么想要直接调用类似的功能,增加代码复用的就用到面向对象编程.
面向对象可以看作一种在程序中包含各种独立而又互相调用的对象的思想.把经常用到的功能变成一个百宝箱,里面有数据和功能(函数),需要用的时候就调用生成一个实例.
类Class在Python中使用class关键字定义类,类里可以存放各种数据和函数.
classshcool:shcool_name=Sanxdeftell_shcool_info(self):print(%s%self.shcool_name)类与对象/实例Object
类里面有各种各样的数据和功能.在做菜的例子中土豆炒肉丝和干扁四季豆,两个都需要放油和放盐.那么就可把这个两个步骤定义为一个功能的集合体,也就是类.当做土豆炒肉丝时,需要放油和放盐时,就直接在定义的类中取就行了,不需要再自己写一遍.
土豆炒肉丝和干扁四季豆的程序就各是一个实例:
class功能:#类def油():放油def盐():放盐干扁四季豆=功能()#实例土豆炒肉丝=功能()#实例
伪代码2:
类狗开始公有成员:吠叫():私有成员:毛皮颜色:品种:结束__init__
函数在定义时是不运行代码的.而类不一样,类在定义时就会运行代码.并产生一个名称空间,里面存放有类体代码中的变量和函数还有类(嵌套).
在实例化的过程中,类体代码是不执行的.想要执行的话,需要将代码放入__init__的函数体中.
classshcool:town=LongShiself.class=[一年级,二年级,三年级,四年级,五年级,六年级]def__init__(self,name,addr)self.name=nameself.addr=addrsanx=shcool(三星小学,中心村)zhongx=shcool(龙市小学,镇街)
在上面的代码中,实例化出了两所小学.这两所小学所在的镇和年级是一样的,所以把相同的数据直接定义好了.而学校的名字和地址不一样,所以在实例化的过程中,写在了__init__函数内,这样在定义的时候就才会执行函数体代码,各种学校的地址也就不一样了.
类的关联在一个程序中类与类是可以互相关联的,第一个类中可以调用第二个类.同理,第二个类也可以调用第一个类的数据和功能.
classlibrary:def__init__(self,name):self.name=nameself.bookclass=[]defadd_bookclass(self,bookclass):self.bookclass.append(bookclass)deftell_bookclass_info(self):print(%s的书架%self.name)print(我喜欢的书籍分类有:,end=)foriinself.bookclass:print(i,end=)print()library_obj1=library(李建钢)library_obj2=library(王素芬)library_obj1.add_bookclass(计算机)library_obj1.add_bookclass(数学)library_obj2.add_bookclass(计算机)library_obj2.add_bookclass(小说)library_obj1.tell_bookclass_info()library_obj2.tell_bookclass_info()
这个类主要是定义了书架的名字和书架上书的种类.这里我创建了李建钢和王素芬两个对象,其中李建钢喜欢数学和计算机,而王素芬喜欢计算机和小说.
classbook:def__init__(self,name,author,price,bookclass):self.book_name=nameself.book_author=authorself.book_price=priceself.bookclass=bookclassdeftell_book_info(self):print(%s作者:%s价格:%s%(self.book_name,self.book_author,self.book_price))book_obj1=book(编码,CharlesPetzold,55.00,计算机)book_obj2=book(数学家讲小学数学,伍鸿熙,78.00,数学)book_obj3=book(活着,余华,20.00,小说)book_obj1.tell_book_info()book_obj2.tell_book_info()book_obj3.tell_book_info()
这个类主要定了书籍的属性,生成了三个对象.
现在这两个类是完全分离的,想要把它们关联起来.注意到这两个类都有bookclass,把它们关联在一起的话,只需要写一个就可以了.在library类中的add_bookclass函数中就可以直接传入book的实例,只要传入了实例,那么实例中的任何数据跟功能都可以使用了.
classlibrary:defadd_bookclass(self,bookclass):self.bookclass.append(bookclass)library_obj1.add_bookclass(book_obj1)library_obj1.add_bookclass(book_obj2)library_obj2.add_bookclass(book_obj1)library_obj2.add_bookclass(book_obj3)print(library_obj1.bookclass)print(library_obj2.bookclass)
现在bookclass里面就不是字符串了,而是book实例化的对象.在下面打印的时候,也就直接调用book内的tellbookinfo函数就ok.
classlibrary:deftell_bookclass_info(self):print(%s的书架%self.name)print(我的书籍:)foriinself.bookclass:print(,i.bookclass,end=)i.tell_book_info()print()library_obj1.tell_bookclass_info()library_obj2.tell_bookclass_info()
现在这两个类产生了关联,我调用library对象的tellbookclassinfo功能,也能访问到book实例化对象的功能了.
类的三大特性:封装,继承,多态封装Encapsulation封装是面向对象三大特性中最核心的一个.什么是封装呢?封装-整合.
封装就是把数据跟功整合在一起放在class里面.需要使用的时候,产生实例,然后调用类里的数据跟功能,但是有的数据跟功能我只是在类里面使用,并不希望被实例访问到,这时候就需要将其隐藏起来.
隐藏属性的方法:在属性名前面加__就行了,注意只前面加,后面不加.这种隐藏在类外部无法访问,但是在类内部是不隐藏的.
classfoo:__x=def__f1(self):print(fromtest)foo.__x#无法访问到foo.__f1
隐藏原理其实很简单,调用foo.__dict__可以得到:
可以看到原来的__x和__f1被Python修改成了_foo__x和_foo__f1.当然无法通过原来的变量名访问到了.但是假如直接用修改后的变量名还是能访问到.
foo._foo__xfoo._foo__f1
这种变形操作只在检查类体代码语法的时候发生一次.后续新增属性加__将不再隐藏.并且隐藏只对类外有效.
继承Inheritance什么是继承?
继承是一种创建新类的方式,新建的类可称为子类或派生类,父类又可称为基类或超类.Python支持多继承,也就是一个类可以继承多个类.子类会继承父类的属性.
classParent1:x=classParent2:passclassSub1(Parent1):#单继承passclassSub2(Parent1,Parent2):#多继承passprint(Sub1.__bases__)#查看父类print(Sub2.__bases__)print(Parent1.__bases__)#父类为objectSub2.x#可以访问到父类Parent1中的x
Python3中所有的类都继承object类.object为Python内置类.
为什么要用继承?
用来解决类与类之间的代码冗余问题.
多继承的优缺点
优点:子类可以同时遗传多个父类的属性,最大限度的重用代码.缺点:代码可读性变差;引发菱形问题.如何使用继承
classStudent:school=SanXdef__init__(self,name,age,sex):self.name=nameself.age=ageself.sex=sexdefchoose_course(self):print(%s的选课功能%self.name)classTeacher:school=SanXdef__init__(self,name,age,sex,salary,level):self.name=nameself.age=ageself.sex=sexself.salary=salaryself.level=leveldefscore(self):print(%s老师正在给学生打分.%self.name)
上面的两个类中,都有school,并且值也相同,出现了代码冗余问题.可以基于继承解决.
#将重复代码提取出来作为父类classSanX:school=SanXdef__init__(self,name,age,sex):self.name=nameself.age=ageself.sex=sex#继承父类SanXclassStudent(SanX):defchoose_course(self):print(%s的选课功能%self.name)classTeacher(SanX):def__init__(self,name,age,sex,salary,level):SanX.__init__(self,name,age,sex)#注意这一步,直接用__init__的话,将递归的查找自己.需要从父类去找.并且只能使用类的方法去调用函数,因为现在还没有实例.self.salary=salaryself.level=leveldefscore(self):print(%s老师正在给学生打分.%self.name)
单继承下的属性查找顺序
classFoo:deff1(self):print(Foo.f1)deff2(self):print(Foo.f2)self.f1()classBar(Foo):deff1(self):print(Bar.f1)obj=Bar()obj.f2()#输出结果为:##Foo.f2#Bar.f1
这里输出是Bar.f1而不是Foo.f1.因为查找顺序为先在自己这里找,自己这里没有再去父类找.
多继承的菱形问题.
大多数面向对象语言都不支持多继承,而在Python中,一个子类是可以同时继承多个父类的,这固然可以带来一个子类可以对多个不同父类加以重用的好处,但也有可能引发著名的Diamondproblem菱形问题(或称钻石问题,有时候也被称为“死亡钻石”),菱形其实就是对下面这种继承结构的形象比喻.
A非object
classA(object):deftest(self):print(fromA)classB(A):deftest(self):print(fromB)classC(A):deftest(self):print(fromC)classD(B,C):passobj=D()obj.test()#输出为fromB
这里的查找顺序为D--B--C--A,可以使用mro函数查看类的查找顺序.
print(D.mro())#[class__main__.D,class__main__.B,class__main__.C,class__main__.A,classobject]
MRO查找机制
子类会优先父类被检查多个父类会根据它们在列表中的顺序被检查如果对下一个类存在两个合法的选择时候,选择第一个父类深度和广度的优先级
非菱形结构:
A--B--E--C--F--D--Object.
一条分支找完,在去下一个分支找.最后找object.
菱形结构:
python2:A--B--E--G--C--F--D--object
python3:A--B--E--C--F--D--G--object
Python2和3的区别,一个一条路走到底,一个是留着最后一个最后走.
super()调用父对象提供给自己的方法.
classSanX:school=SanXdef__init__(self,name,age,sex):self.name=nameself.age=ageself.sex=sexclassTeacher(SanX):def__init__(self,name,age,sex,salary,level):#SanX.__init__(self,name,age,sex)原来调用方法,直接找类名super().__init__(name,age,sex)#使用super(),参照mro从父类开始找,跳过自己.self.salary=salaryself.level=level多态Polymorphism
什么是多态?
同一种事物有多种形态,比如水的三种形态:固态,液态,气态.
classAnimal:passclassPeople(Animal):passclassDog(Animal):passclassPig(Animal):pass
多态的特性
classAnimal:defsay(delf):print(动物发出声音.....)classPeople(Animal):defsay(self):super().say()print(吃了没)classDog(Animal):defsay(self):super().say()print(汪汪汪)classPig(Animal):defsay(self):super().say()print(哼哼哼)
多态性指的是可以在不考虑对象具体类型的情况下,直接使用对象.
obj1=People()obj2=Dog()obj3=Pig()#obj1,2,3都有say()的功能obj1.say()obj2.say()obj3.say()wezhon