一,初始面向对象
面向过程的程序设计的核心是过程(流水线式思维),过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西。
优点是:极大的降低了写程序的复杂度,只需要顺着要执行的步骤,堆叠代码即可。
缺点是:一套流水线或者流程就是用来解决一个问题,代码牵一发而动全身。
应用场景:一旦完成基本很少改变的场景,著名的例子有Linux內核,git,以及Apache HTTP Server等
类:(定义)
具有相同属性或技能的一类事物
而类有两种属性:静态属性和动态属性
静态属性就是直接在类中定义的变量
动态属性就是定义在类中的方法
对象: 具体类的表现
类体: 有两部分组成
1, 静态变量(静态属性)
普通属性和静态属性,他们在定义和使用中有所区别,而最本质的区别是内存中保存的位置不同
普通属性属于对象
静态属性属于类
2,方法(动态属性)
方法包括:普通方法、静态方法和类方法,三种方法在内存中都归属于类,区别在于调用方式不同。
普通方法:由对象调用;至少一个self参数;执行普通方法时,自动将调用该方法的对象赋值给self
类方法:由类调用; 至少一个cls参数;执行类方法时,自动将调用该方法的类复制给cls;
- 静态方法:由类调用;无默认参数;
类名.__dict__查询类中所有内容(不能增,删,改)
类名.新变量=内容 增
类名.变量=新内容 改
del 类名.变量 删
类名+() 这个过程: 是实例化的一个过程(创建了一个对象)
类名() 实例化对象
实行了三步
1,产生了一个实例 (对象,对象空间)
2,把对象空间传给self ,执行__init__方法
3,把这个对象的空间返回给调用者
对象的角度:
对象.__dict__ 查询对象中的所有内容
万能的点,可以修改对象中的所有内容
对象操作类中的静态变量:只能查询和引用
对象调用类中的方法[工作中通过对象执行类中的方法,而不是通过类名]
对象空间和对象空间是相互独立的
1,静态属性(静态变量,静态字段)
2,动态属性(方法) self
3,类方法 @classmethod 默认参数:cls
4,静态方法 @staticmethod 没有默认参数
5,特性 @property 引入它是为了让方法伪装成一个属性,在代码上没有本质的提升 其实就是普通方法的变种 (详细讲解在属性那篇博客中)
调用
对象名.动态属性()/类名.动态属性() 需要传参
类名.静态变量(静态属性)/对象名.静态变量(静态属性)
类名.类方法()/对象名.类方法() 不需要传入参数
类名.静态方法()/对象名.静态方法()
操作类中的方法(除了类方法,静态方法 需要类名调用之外,剩下的方法都要对象调用)
以上调用优先前面的一种
对象的命名空间中能存:
对象属性
对象能调用的:
对象属性
类中的普通方法
组合 (让对象和对象之间发生关系)
给一个类的对象封装一个属性,这个属性是另一个类的对象
对象.属性 : 先从对象空间中查找,找到到去本类空间查找,然后是父类查找...
类名.属性: 先从本类中查找,找不到再从父类中查找.... 它无法查找对象空间的属性
面向对象的三大属性 : 继承,多态,封装
object
类: 分为新式类和经典类
凡是继承object类型的类都是新式类,否则都是经典类
python 2X:(既有经典类,又有新式类,所有的类都默认不继承object类,都默认为经典类,但是可以叫他继承object)
python 3X (所有的类都为新式类,因为python 3X 默认都继承object)
class Person(Animal): 括号里的是父类(基类,超类) 括号外的是派生类(子类)
pass
子类类名和子类实例化的对象可以访问父类的所有内容
只执行父类的方法: 子类就不要定义与父类同名的方法
只执行子类的方法: 在子类创建这个方法
既要执行子类方法,又要执行父类方法(两种解决方案)
1,父类名.__init__(self,name,sex,age)
2,super().__init__(name,sex,age) [其中super(子类名,self) 一般默认 ,不用打出来]
class Animal: def __init__(self,name,sex,age): self.name=name self.sex=sex self.age=age def eat(self): print('%s都需要进食'% self.name) def drink(self): print('%s都需要饮水'% self.name) class Brid(Animal): def __init__(self,name,sex,age,wing): # Animal.__init__(self,name,sex,age) super().__init__(name,sex,age) self.wing=wing def laying_eggs(self): print('可以产蛋') def eat(self): # Animal.eat(self) super().eat() print('%s都需要吃虫子'% self.name) class Cat(Animal): def mousetrap(self): print('可以抓老鼠') class Dog(Animal): def housekeeping(self): print('可以看家') b1=Brid('鹦鹉','公',16,'绿翅膀') b1.eat()
继承:
单继承: 新式类和经典类查询顺序一样
多继承:新式类:广度优先
经典类:深度优先
多继承广度优先 根据mro-c3算法 可以用mro方法查看继承顺序
为什么会有继承:
1,提高代码的复用性
2,提高代码的维护性
3,让类与类发生关系
A(B,C,D) #首先找到A继承的三个类的深度继承顺序,放到一个列表中 L[B] = [B,D,F,H] #B往上面的继承顺序 L[C] = [C,E,G,H] #C往上面的继承顺序 L[D] = [D,F,H] #D往上面的继承顺序 #第二步:A自己的广度,第一层 L[A] = [B,C,D] list = [A,B,C,D,F,E,G,H,O] #每个列表的第一个元素为头部,从第一个列表的头部开始找,找其他列表中尾部是否含有 这个类名,如果没有,提取出来放到一个列表中,如果有,找下一个列表的头部,循环下去 只要提取来一个,我们就从第一个列表的头部接着重复上面的操作. 1 [B,D,F,H] [C,E,G,H] [D,F,H] [B,C,D] 2 [D,F,H] [C,E,G,H] [D,F,H] [C,D] #提取了头部的B,然后将其他列表头部的B删除,并将B放到list中 3 [D,F,H] [E,G,H] [D,F,H] [D] #因为第一个列表的D在其他列表的尾部存在,所以跳过D,然后找第二个列表的头部C,提取了头部的C,然后将其他列表头部的B删除,并将B放到list中 4 [H] [H] [H] [] 第二题 #最高树杈的mro继承顺序 B 1 [B] [E] [D] [E,D] 2 [] [E] [D] [E,D] 3 [] [] [D] [D] list_B = [B,E,D] c 1 [C] [D] [F] [D,F] 2 [] [D] [F] [D,F] 3 [] [] [F] [F] list_C = [C,D,F] A 1 [A] [B,E,D] [C,D,F] [B,C] 2 [] [B,E,D] [C,D,F] [B,C] 3 [] [E,D] [C,D,F] [C] 4 [] [D] [C,D,F] [C] 5 [] [D] [D,F] [] 6 [] [] [F] [] 6 [] [] [] [] list_A [A,B,E,C,D,F]
多态:
python 没有多态,因为他处处都是多态(但是他有鸭子类型)
鸭子类型: 他看着像鸭子,他就是鸭子 (类中都有相同的方法,那么这些类就互称为鸭子
lass F1: pass class S1(F1): def show(self): print 'S1.show' class S2(F1): def show(self): print 'S2.show' def Func(obj): print obj.show() s1_obj = S1() Func(s1_obj) s2_obj = S2() Func(s2_obj) Python “鸭子类型”
抽象类与接口类
与java一样,python也有抽象类的概念但是同样需要借助模块实现,抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化
为什么要有抽象类
如果说类是从一堆对象中抽取相同的内容而来的,那么抽象类就是从一堆类中抽取相同的内容而来的,内容包括数据属性和函数属性。
比如我们有香蕉的类,有苹果的类,有桃子的类,但从这些类抽取相同的内容就是水果的类,吃水果时,要么吃一个具体的香蕉,要么吃一个具体的桃子, 但你永远吃不到一个叫水果的东西.
从设计角度来看,如果类是从现实对象抽象而来,那么抽象类就是基于类抽象而来.
从实现角度来看,抽象类与普通类的不同之处在于:抽象类中有抽象方法,该类不能被实例化,只能被继承,且子类必须实现抽象方法,这一点和接口有点相似,但其实不同
from abc import ABCMeta ,abstractmethod class Payment (metaclass=ABCMeta): @abstractmethod #制定一个,就需要引用一次 def pay(self): #制定规范 pass class Alipay(Payment): def __init__(self,money): self.money=money def pay(self): print('用支付宝支付了%d元' % self.money) class Jdpay(Payment): def __init__(self,money): self.money=money def pay(self): print('用京东支付了%d元' % self.money) def pay(abc): # 归一化设计 abc.pay() a1=Alipay(100) j1=Jdpay(1000) pay(a1) pay(j1)
封装
广义的封装 : 把方法和属性都封装在一个类里,定义一个规范来描述一类事物.
狭义的封装 : 私有化 只能在类的内部访问
__静态变量,私有方法,私有的对象属性,私有的类方法,私有的静态方法
在内存中存储 _类名__名字
为什么在类的内部可以使用双下划线访问 : 在类的内部使用,你就知道你在哪个类中
在子类中可以访问访问父类的私有变量么?不行
私有 : 不能在类的外部使用也不能被继承
浙公网安备 33010602011771号