参考:https://www.cnblogs.com/Eva-J/articles/7293890.htm#_label14html
讲解及其详细。你们能够直接去看原创。python
Python中一切皆为对象。git
面向对象编程简单来讲就是基于对 类 和 对象 的使用,全部的代码都是经过类和对象来实现的编程就是面向对象编程!程序员
类:一个模板,模板里能够包含多个函数,函数里实现一些功能。具备相同特征的一类事物。编程
对象(实例):根据模板建立的实例,经过实例对象能够执行类中的函数。具体的某一个事物。python3.x
属性:事务的特征。好比好比年龄、身高、性别、姓名等都叫作属性,一个类中,能够有多个属性。安全
方法:人类不止有身高、年龄、性别这些属性,还能作好多事情,好比说话、走路、吃饭等,相比较于属性是名词,说话、走路是动词,这些动词用程序来描述就叫作方法。app
实例化:类——>对象的过程。编程语言
在python中,用变量表示特征,用函数表示技能,于是具备相同特征和技能的一类事物就是‘类’,对象是则是这一类事物中具体的一个。函数
核心是过程二字,过程指的是解决问题的步骤,比如如设计一条流水线,是一种机械式的思惟方式。
就是程序从上到下一步步执行,一步步从上到下,从头至尾的解决问题 。
基本设计思路就是程序一开始是要着手解决一个大的问题,而后把一个大问题分解成不少个小问题或子过程,这些子过程再执行的过程再继续分解直到小问题足够简单到能够在一个小步骤范围内解决。
优势
将复杂的问题流程化,进而简单化;
极大的下降了写程序的复杂度,只须要顺着要执行的步骤,堆叠代码便可。
缺点
扩展性差;
代码牵一发而动全身。
应用场景
一旦完成基本不多改变的场景,著名的例子有Linux內核,git,以及Apache HTTP Server等
核心是对象二字,特征和技能的结合体。
优势
可扩展性高;
对某一个对象单独修改,会马上反映到整个体系中,如对游戏中一我的物参数的特征和技能修改都很容易。
缺点
编程复杂度高;
可控性差,没法向面向过程的程序设计流水线式的能够很精准的预测问题的处理流程与结果,
面向对象的程序一旦开始就由对象之间的交互解决问题,即使是上帝也没法预测最终结果。
因而咱们常常看到一个游戏人某一参数的修改极有可能致使阴霸的技能出现,一刀砍死3我的,这个游戏就失去平衡。
应用场景
需求常常变化的软件,通常需求的变化都集中在用户层,互联网应用,企业内部软件,游戏等都是面向对象的程序设计大显身手的好地方。
class 类名: def __init__(self,参数1,参数2): self.对象的属性1 = 参数1 self.对象的属性2 = 参数2 def 方法名(self):pass def 方法名2(self):pass 对象名 = 类名(1,2) #对象就是实例,表明一个具体的东西 #类名() : 类名+括号就是实例化一个类,至关于调用了__init__方法 #括号里传参数,参数不须要传self,其余与init中的形参一一对应 #结果返回一个对象 对象名.对象的属性1 #查看对象的属性,直接用 对象名.属性名 便可 对象名.方法名() #调用类中的方法,直接用 对象名.方法名() 便可
class Dog: # 定义一个狗类 role = 'dog' # 狗的角色属性都是狗 def __init__(self, name, breed, aggressivity, life_value): self.name = name # 每一只狗都有本身的昵称; self.breed = breed # 每一只狗都有本身的品种; self.aggressivity = aggressivity # 每一只狗都有本身的攻击力; self.life_value = life_value # 每一只狗都有本身的生命值;
ha2 = Dog('二愣子','哈士奇',10,1000) #创造了一只实实在在的狗ha2 #对象就是实例,表明一个具体的东西 #类名() : 类名+括号就是实例化一个类,至关于调用了__init__方法 #括号里传参数,参数不须要传self,其余与init中的形参一一对应 #结果返回一个对象
class Person: # 定义一我的类 role = 'person' # 人的角色属性都是人 def __init__(self, name, aggressivity, life_value): self.name = name # 每个角色都有本身的昵称; self.aggressivity = aggressivity # 每个角色都有本身的攻击力; self.life_value = life_value # 每个角色都有本身的生命值; def attack(self,dog): # 人能够攻击狗,这里的狗也是一个对象。 # 人攻击狗,那么狗的生命值就会根据人的攻击力而降低 dog.life_value -= self.aggressivity class Dog: # 定义一个狗类 role = 'dog' # 狗的角色属性都是狗 def __init__(self, name, breed, aggressivity, life_value): self.name = name # 每一只狗都有本身的昵称; self.breed = breed # 每一只狗都有本身的品种; self.aggressivity = aggressivity # 每一只狗都有本身的攻击力; self.life_value = life_value # 每一只狗都有本身的生命值; def bite(self,people): # 狗能够咬人,这里的狗也是一个对象。 # 狗咬人,那么人的生命值就会根据狗的攻击力而降低 people.life_value -= self.aggressivity egg = Person('egon',10,1000) #创造了一个实实在在的人egg ha2 = Dog('二愣子','哈士奇',10,1000) #创造了一只实实在在的狗ha2 print(ha2.life_value) #看看ha2的生命值 egg.attack(ha2) #egg打了ha2一下 print(ha2.life_value) #ha2掉了10点血
建立一个类就会建立一个类的名称空间,用来存储类中定义的全部名字,这些名字称为类的属性。
而类有两种属性:静态属性和动态属性
id(egg.role) == id(Person.role) #out:True
egg.attack == Person.attack #out:Fales
建立一个对象/实例就会建立一个对象/实例的名称空间,存放对象/实例的名字,称为对象/实例的属性
在obj.name会先从obj本身的名称空间里找name,找不到则去类中找,类也找不到就找父类...最后都找不到就抛出异常。
软件重用的重要方式除了继承以外还有另一种方式,即:组合
组合指的是,在一个类中以另一个类的对象做为数据属性,称为类的组合。
class BirthDate: def __init__(self,year,month,day): self.year=year self.month=month self.day=day class Couse: def __init__(self,name,price,period): self.name=name self.price=price self.period=period class Teacher: def __init__(self,name,gender,birth,course): self.name=name self.gender=gender self.birth=birth self.course=course def teach(self): print('teaching') p1=Teacher('egon','male', BirthDate('1995','1','27'), Couse('python','28000','4 months') ) print(p1.birth.year,p1.birth.month,p1.birth.day) #out: 1995 1 27 print(p1.course.name,p1.course.price,p1.course.period) #out:python 28000 4 months
当类之间有显著不一样,而且较小的类是较大的类所须要的组件时,用组合比较好。
继承是一种建立新类的方式,在python中,新建的类能够继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类
在类名后面括号中写上另外一个类,表示继承了那个类。
抽象即抽取相似或者说比较像的部分。
抽象分红两个层次:
1.将奥巴马和梅西这俩对象比较像的部分抽取成类;
2.将人,猪,狗这三个类比较像的部分抽取成父类。
抽象最主要的做用是划分类别(能够隔离关注点,下降复杂度)
继承:是基于抽象的结果,经过编程语言去实现它,确定是先经历抽象这个过程,才能经过继承的方式去表达出抽象的结构。
抽象只是分析和设计的过程当中,一个动做或者说一种技巧,经过抽象能够获得类
class ParentClass1: #定义父类 pass class ParentClass2: #定义父类 pass class SubClass1(ParentClass1): #单继承,基类是ParentClass1,派生类是SubClass pass class SubClass2(ParentClass1,ParentClass2): #python支持多继承,用逗号分隔开多个继承的类 pass #__base__只查看从左到右继承的第一个子类,__bases__则是查看全部继承的父类 print(SubClass1.__bases__) #out:(<class '__main__.ParentClass1'>,) print(SubClass2.__bases__) #out:(<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>) #若是没有指定基类,python的类会默认继承object类,object是全部python类的基类,它提供了一些常见方法(如__str__)的实现。 print(ParentClass1.__bases__) #out:(<class 'object'>,)
在python中,类还能够继承多个类,在继承多个类时,他对类中的函数查找有两种方式
深度优先:类是经典类时,多继承状况下,会按照深度优先方式查找
广度优先:类是新式类时,多继承状况下,会按照广度优先方式查找
(在python3.x中)都默认为广度优先,但仍是能够了解一下两个的区别,新式类:当前类或者基类继承了objiect类就叫新式类,否者就是经典类。
class A(object): def name(self): print("HELLO") class B(A): pass class C(A): def name(self): print("PYTHON") class D(B,C): pass a1=D() a1.name() #输出:PYTHON #查找顺序:# 首先去本身D类中查找,若是没有,则继续去B类中找,没有则继续去C类中找,没有则继续去A类中找,若是仍是未找到,则报错 #广度优先:D-B-C-A
#深度优先:D-B-A-C
class A(object): def test(self): print('from A') class B(A): def test(self): print('from B') class C(A): def test(self): print('from C') class D(B): def test(self): print('from D') class E(C): def test(self): print('from E') class F(D,E): # def test(self): # print('from F') pass f1=F() f1.test() #out:from D print(F.__mro__) #只有新式才有这个属性能够查看线性列表,经典类没有这个属性 #新式类继承顺序:F->D->B->E->C->A #经典类继承顺序:F->D->B->A->E->C #python3中统一都是新式类 #pyhon2中才分新式类与经典类 继承顺序
在python3中,子类执行父类的方法也能够直接用super方法。
super() 函数是用于调用父类(超类)的一个方法。
基本语法:super(type,[object-or-type])
type: 类
object-or-type:类,通常是 self
super().xxx 代替 super(Class, self).xxx
参考:http://www.javashuo.com/article/p-ztarpcjs-ea.html
class A(): def go(self): print ("go A go!") def stop(self): print ("stop A stop!") def pause(self): raise Exception("Not Implemented") class B(A): def go(self): super(B, self).go() print ("go B go!") class C(A): def go(self): super(C, self).go() print ("go C go!") def stop(self): super(C, self).stop() print ("stop C stop!") class D(B,C): def go(self): super(D, self).go() print ("go D go!") def stop(self): super(D, self).stop() print ("stop D stop!") def pause(self): print ("wait D wait!") class E(B,C): pass a = A() b = B() c = C() d = D() e = E() # 说明下列代码的输出结果 a.go()# go A go! b.go()# go A go!# go B go! c.go()# go A go!# go C go! d.go()# go A go!# go C go!# go B go!# go D go! e.go()# go A go!# go C go!# go B go! a.stop()# stop A stop! b.stop()# stop A stop! c.stop()# stop A stop!# stop C stop! d.stop()# stop A stop!# stop C stop!# stop D stop! e.stop()# stop A stop!# stop C stip! print(D.mro()) a.pause()# ... Exception: Not Implemented b.pause()# ... Exception: Not Implemented c.pause()# ... Exception: Not Implemented d.pause()# wait D wait! e.pause()# ...Exception: Not Implemented
子类能够添加本身新的属性或者在本身这里从新定义这些属性(不会影响到父类),须要注意的是,一旦从新定义了本身的属性且与父类重名,那么调用新增的属性时,就以本身为准了。
class Animal: ''' 人和狗都是动物,因此创造一个Animal基类 ''' def __init__(self, name, aggressivity, life_value): self.name = name # 人和狗都有本身的昵称; self.aggressivity = aggressivity # 人和狗都有本身的攻击力; self.life_value = life_value # 人和狗都有本身的生命值; def eat(self): print('%s is eating'%self.name) class Dog(Animal): ''' 狗类,继承Animal类 ''' def bite(self, people): ''' 派生:狗有咬人的技能 :param people: ''' people.life_value -= self.aggressivity class Person(Animal): ''' 人类,继承Animal ''' def attack(self, dog): ''' 派生:人有攻击的技能 :param dog: ''' dog.life_value -= self.aggressivity egg = Person('egon',10,1000) ha2 = Dog('二愣子',50,1000) print(ha2.life_value) #out:1000 print(egg.attack(ha2)) #out:None print(ha2.life_value) #out:990
像ha2.life_value之类的属性引用,会先从实例中找life_value而后去类中找,而后再去父类中找...直到最顶级的父类。
继承有两种用途:
接口继承实质上是要求“作出一个良好的抽象,这个抽象规定了一个兼容接口,使得外部调用者无需关心具体细节,可一视同仁的处理实现了特定接口的全部对象”——这在程序设计上,叫作归一化。
归一化,让使用者无需关心对象的类是什么,只须要的知道这些对象都具有某些功能就能够了,这极大地下降了使用者的使用难度。
class Alipay: ''' 支付宝支付 ''' def pay(self,money): print('支付宝支付了%s元'%money) class Applepay: ''' apple pay支付 ''' def pay(self,money): print('apple pay支付了%s元'%money) def pay(payment,money): ''' 支付函数,整体负责支付 对应支付的对象和要支付的金额 ''' payment.pay(money) p = Alipay() pay(p,200) #out: 支付宝支付了200元
抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化。
若是说类是从一堆对象中抽取相同的内容而来的,那么抽象类就是从一堆类中抽取相同的内容而来的,内容包括数据属性和函数属性。
抽象类的本质仍是类,指的是一组类的类似性,包括数据属性(如all_type)和函数属性(如read、write),而接口只强调函数属性的类似性。
抽象类是一个介于类和接口直接的一个概念,同时具有类和接口的部分特性,能够用来实现归一化设计
在python中,并无接口类这种东西,即使不经过专门的模块定义接口,咱们也应该有一些基本的概念。
在继承抽象类的过程当中,咱们应该尽可能避免多继承;
而在继承接口的时候,咱们反而鼓励你来多继承接口。
接口隔离原则: 使用多个专门的接口,而不使用单一的总接口。即客户端不该该依赖那些不须要的接口。
在抽象类中,咱们能够对一些抽象方法作出基础实现;
而在接口类中,任何方法都只是一种规范,具体的功能须要子类实现。
.
多态指的是一类事物有多种形态
动物有多种形态:人,狗,猪
文件有多种形态:文本文件,可执行文件
在面向对象方法中通常是这样表述多态性:
向不一样的对象发送同一条消息(!!!obj.func():是调用了obj的方法func,又称为向obj发送了一条消息func),不一样的对象在接收时会产生不一样的行为(即方法)。
也就是说,每一个对象能够用本身的方式去响应共同的消息。所谓消息,就是调用函数,不一样的行为就是指不一样的实现,即执行不一样的函数。
好比:老师.下课铃响了(),学生.下课铃响了(),老师执行的是下班操做,学生执行的是放学操做,虽然两者消息同样,可是执行的效果不一样
Python崇尚鸭子类型,即‘若是看起来像、叫声像并且走起路来像鸭子,那么它就是鸭子
隐藏对象的属性和实现细节,仅对外提供公共访问方式。
在python中用双下划线开头的方式将属性隐藏起来(设置成私有的)
#其实这仅仅这是一种变形操做 #类中全部双下划线开头的名称如__x都会自动变造成:_类名__x的形式: class A: __N=0 #类的数据属性就应该是共享的,可是语法上是能够把类的数据属性设置成私有的如__N,会变形为_A__N 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是能够访问到的,即这种操做并非严格意义上的限制外部访问,仅仅只是一种语法意义上的变形
这种自动变形的特色:
1.类中定义的__x只能在内部使用,如self.__x,引用的就是变形的结果。
2.这种变形其实正是针对外部的变形,在外部是没法经过__x这个名字访问到的。
3.在子类定义的__x不会覆盖在父类定义的__x,由于子类中变造成了:_子类名__x,而父类中变造成了:_父类名__x,即双下滑线开头的属性在继承给子类时,子类是没法覆盖的。
这种变形须要注意的问题是:
1.这种机制也并无真正意义上限制咱们从外部直接访问属性,知道了类名和属性名就能够拼出名字:_类名__属性,而后就能够访问了,如a._A__N
2.变形的过程只在类的内部生效,在定义后的赋值操做,不会变形
在python中用双下划线开头的方式将属性隐藏起来(设置成私有的)
在继承中,父类若是不想让子类覆盖本身的方法,能够将方法定义为私有的
#正常状况 >>> class A: ... def fa(self): ... print('from A') ... def test(self): ... self.fa() ... >>> class B(A): ... def fa(self): ... print('from B') ... >>> b=B() >>> b.test() #out:from B #将B.fa更名 >>> class A: ... def fa(self): ... print('from A') ... def test(self): ... self.fa() ... >>> class B(A): ... def fb(self): ... print('from B') ... >>> b=B() >>> b.test() #out:from A #把fa定义成私有的,即__fa >>> class A: ... def __fa(self): #在定义时就变形为_A__fa ... print('from A') ... def test(self): ... self.__fa() #只会与本身所在的类为准,即调用_A__fa ... >>> class B(A): ... def __fa(self): ... print('from B') ... >>> b=B() >>> b.test() #out:from A 在“正常状况”下: b.test 调用函数fa,先在子类B中查找并找到。因此输出 “from B”。 在“将B.fa更名”下:b.test 调用函数fa,先在子类B中查找但未找到,进而从父类A中查找并找到。因此输出 “from A”。 在“把fa定义成私有的,即__fa”: b.test 调用函数fa,先在子类B中查找由于私有化而没法找到,进而从父类A中查找(test也在A类中)并找到。 因此输出 “from A”。
封装在于明确区份内外,使得类实现者能够修改封装内的东西而不影响外部调用者的代码;
而外部使用用者只知道一个接口(函数),只要接口(函数)名、参数不变,使用者的代码永远无需改变。
这就提供一个良好的合做基础——或者说,只要接口这个基础约定不变,则代码改变不足为虑。
#类的设计者 class Room: def __init__(self,name,owner,width,length,high): self.name=name self.owner=owner self.__width=width self.__length=length self.__high=high def tell_area(self): #对外提供的接口,隐藏了内部的实现细节,此时咱们想求的是面积 return self.__width * self.__length #使用者 >>> r1=Room('卧室','egon',20,20,20) >>> r1.tell_area() #使用者调用接口tell_area #类的设计者,轻松的扩展了功能,而类的使用者彻底不须要改变本身的代码 class Room: def __init__(self,name,owner,width,length,high): self.name=name self.owner=owner self.__width=width self.__length=length self.__high=high def tell_area(self): #对外提供的接口,隐藏内部实现,此时咱们想求的是体积,内部逻辑变了,只需求修该下列一行就能够很简答的实现,并且外部调用感知不到,仍然使用该方法,可是功能已经变了 return self.__width * self.__length * self.__high #对于仍然在使用tell_area接口的人来讲,根本无需改动本身的代码,就能够用上新功能 >>> r1.tell_area()
参考:http://www.javashuo.com/article/p-kjdshexe-q.html
class Goods: def __init__(self): # 原价 self.original_price = 100 # 折扣 self.discount = 0.8 @property def price(self): # 实际价格 = 原价 * 折扣 new_price = self.original_price * self.discount return new_price @price.setter def price(self, value): self.original_price = value @price.deleter def price(self): del self.original_price obj = Goods() obj.price # 获取商品价格 obj.price = 200 # 修改商品原价 print(obj.price) del obj.price # 删除商品原价
将一个类的函数定义成特性之后,对象再去使用的时候obj.name,根本没法察觉本身的name是执行了一个函数而后计算出来的,这种特性的使用方式遵循了统一访问的原则
import module_name
from module_name import class_name
from module_name import class_name1,class_name2
from module_name import *
不建议使用
模块能够嵌套;类也能够嵌套。
抽象/实现
抽象指对现实世界问题和实体的本质表现,行为和特征建模,创建一个相关的子集,能够用于 绘程序结构,从而实现这种模型。抽象不只包括这种模型的数据属性,还定义了这些数据的接口。
对某种抽象的实现就是对此数据及与之相关接口的现实化(realization)。现实化这个过程对于客户 程序应当是透明并且无关的。
封装/接口
封装描述了对数据/信息进行隐藏的观念,它对数据属性提供接口和访问函数。经过任何客户端直接对数据的访问,无视接口,与封装性都是背道而驰的,除非程序员容许这些操做。做为实现的 一部分,客户端根本就不须要知道在封装以后,数据属性是如何组织的。在Python中,全部的类属性都是公开的,但名字可能被“混淆”了,以阻止未经受权的访问,但仅此而已,再没有其余预防措施了。这就须要在设计时,对数据提供相应的接口,以避免客户程序经过不规范的操做来存取封装的数据属性。
注意:封装毫不是等于“把不想让别人看到、之后可能修改的东西用private隐藏起来”
真正的封装是,通过深刻的思考,作出良好的抽象,给出“完整且最小”的接口,并使得内部细节能够对外透明
(注意:对外透明的意思是,外部调用者能够顺利的获得本身想要的任何功能,彻底意识不到内部细节的存在)
合成
合成扩充了对类的 述,使得多个不一样的类合成为一个大的类,来解决现实问题。合成 述了 一个异常复杂的系统,好比一个类由其它类组成,更小的组件也多是其它的类,数据属性及行为, 全部这些合在一块儿,彼此是“有一个”的关系。
派生/继承/继承结构
派生描述了子类衍生出新的特性,新类保留已存类类型中全部须要的数据和行为,但容许修改或者其它的自定义操做,都不会修改原类的定义。
继承描述了子类属性从祖先类继承这样一种方式
继承结构表示多“代”派生,能够述成一个“族谱”,连续的子类,与祖先类都有关系。
泛化/特化
基于继承
泛化表示全部子类与其父类及祖先类有同样的特色。
特化描述全部子类的自定义,也就是,什么属性让它与其祖先类不一样。
多态与多态性
多态指的是同一种事物的多种状态:水这种事物有多种不一样的状态:冰,水蒸气
多态性的概念指出了对象如何经过他们共同的属性和动做来操做及访问,而不需考虑他们具体的类。
冰,水蒸气,都继承于水,它们都有一个同名的方法就是变成云,可是冰.变云(),与水蒸气.变云()是大相径庭的过程,虽然调用的方法都同样
自省/反射
自省也称做反射,这个性质展现了某对象是如何在运行期取得自身信息的。若是传一个对象给你,你能够查出它有什么能力,这是一项强大的特性。若是Python不支持某种形式的自省功能,dir和type内建函数,将很难正常工做。还有那些特殊属性,像__dict__,__name__及__doc__