面向对象的程序设计
--------------------------------------------------------------------------------------------------------------------
·1940年以前:面向机器
直接使用机器语言(直接编写0和1)编写程序,执行速度快,但是容易写错,难以修改,编写效率底。其后发展出了汇编语言(符号语言)用助记符号替代机器指令的操作码,提升了代码可读性,但仍然是面向机器的语言,编写同样困难。
·脱离机器第一步:面向过程
面向过程语言:不再关注机器本身的操作指令,储存等方面,而是关注如何一步一步的解决具体的问题,即解决问题的过程。具备可移植性和同用性,更加容易编写和维护。
·结构化程序设计
大部分面向过程语言中的goto语句导致的面条式代码,极大的限制了程序的规模。结构化程序设计抛弃 goto 语句,采取“自顶向下、逐步细化、模块化”的指导思想。
·面向对象程序设计
随着硬件和业务的发展,软件的可拓展性和可维护性问题亟待解决。面向对象程序设计开始流行,面向对象的思想更加贴近人类思维的特点。
------------------------------------------------------------------------------------------------------------------------
面向过程的程序设计:
优点:复杂问题流程化,进而简单化。
缺点:一套流程解决一个问题,可拓展性差。牵一发动全身。
面向对象的程序设计:
对象:属性与功能的结合体
优点:解决程序的拓展性。对一个对象单独修改,立刻反映到整体。
缺点:
1.编程复杂度提高。容易出现过度设计的问题。
2.无法精确的预测问题的处理流程与结果。取决于对象之间的交互。
面向对象的程序设计并不是全部。对于一个软件质量来说,面向对象的程序设计只是用来解决扩展性。
类:一系列属性与功能相似的对象的结合体。
现实逻辑中先有对象再有类,但是在程序中务必保证先定义类,后产生对象。
class test: #定义类 x=1 #定义类的属性 y=2 def learn(self,*args,**kwargs): #定义类的功能 print(self,args,kwargs) def ttt(): print('from ttt') obj1 = test() #根据类自定义对象 obj1.x = 123 #对象可以定义自己属性,如与类定义冲突则覆盖 print(obj1.x) >>>123 obj1.name = ttt #对象可以定义自己功能,如与类定义冲突则覆盖 print(obj1.name()) >>>from ttt >>>None print(obj1.y) #对象也可以调用类的属性 >>>2 obj1.learn(test.x,1,2,3,a = 6) #对象可以调用类的功能 >>><__main__.test object at 0x00000000021392E8> (1, 1, 2, 3) {'a': 6} print(obj1.__dict__) #__dict__查看对象或类的属性 >>>{'x': 123, 'name': <function ttt at 0x0000000001D42EA0>}
class bmw: x=1 y=2 def __init__(obj,a,b,c): obj.name=a obj.age=b obj.sex=c obj1=bmw(1,2,3) print(obj1.age)
Python中一些类的特殊属性
类的两种属性:数据属性和函数属性
1.类的数据属性是所以对象共享的
2 类的函数属性是绑定给对象用的(类中定义的函数都要定义默认写一个参数self绑定对象)
面向对象之继承与派生
继承:继承是一种是一种创建新类的方式,新建的类可以继承一个或多个父类(python支持多继承),父类又称为基类或超类,新建的类称为派生类或子类。子类会继承父类的属性,从而解决代码重用的问题
一生二 ,二生三,三生万物。
继承过程中注意覆盖!
在子类中,新建的重名的函数属性,在编辑函数内功能的时候,有可能需要重用父类中重名的那个函数功能,应该是用调用普通函数的方式,即:类名.func(),此时就与调用普通函数无异了,因此即便是self参数也要为其传值
class father: def run(self,x): print('%s is father run' % x) class son(father): def run(self,x,y): print('%s is son run' % y) father.run(self,x) a = son() a.run('123','456')
在一个类中以另外一个类的对象作为数据属性,称为类的组合
抽象类就是从一堆类中抽取相同内容而来的,它是一个特殊类,它的特殊之处在于它只能被继承,不能被实例化。且子类必须实现抽象方法。
抽象类的实现
继承实现的原理 PS:图片引用自linghaifeng博客
对于自定义的每一个类,Python会计算出一个方法解析顺序(MRO)列表,就是一个简单的所有基类的线性顺序列表可用__mro__查看。Python会从左到右开始查找基类,直到找到第一匹配这个属性的类为止。MRO列表遵循下列三条原则
1,子类会先与父类被检查
2,多个父类会根据他们在列表中的顺序被检查
3,如果对下一个类存在两个合法的选择,选择第一个父类


接口:
java中interface很好的体现了接口的特征;接口是一组功能的集合,而不是一个功能;接口的功能用于交互,所有的对象都是public,即别的对象可操作;接口只定义函数,但不涉及函数的实现;这些功能是相关的。
基于同一接口实现的类,那么所有这些类在产生对象时,从用法上来说都是一样的,我把它理解为一种‘统一的标准’
子类调用父类的方法:
1,直接用父类的名称加方法名称调用,与普通函数调用类似
2,super,直接指定父类名,如果没有继承关系,super还是会按照mro继续往后找。 super(类名,self)=func()
多态:一类事物的多种形态
多态性:向不同的对象发送同一信息,不同的对象在接收时会产生不同的行为
import abc class anime(metaclass=abc.ABCMeta): @abc.abstractmethod def talk(self): self.talk() class Cat(anime): def talk(self): print('miao miao miao') class Dog(anime): def talk(self): print('wan wan wan') class Dark(anime): def talk(self): print('ga ga ga') # def talk(anime): # anime.talk() c1=Cat() d1=Dog() dark1 = Dark() # talk(d1) c1.talk()
封装:隔离属性,提供接口,隔离复杂度,提高安全性
真正的封装是,经过深入的思考,做出良好的抽象,给出“完整且最小”的接口,并使得内部细节可以对外透明
属性私有化__func(),对外接口 _A__func()
#取款是功能,而这个功能有很多功能组成:插卡、密码认证、输入金额、打印账单、取钱 #对使用者来说,只需要知道取款这个功能即可,其余功能我们都可以隐藏起来,很明显这么做 #隔离了复杂度,同时也提升了安全性 class ATM: def __card(self): print('插卡') def __auth(self): print('用户认证') def __input(self): print('输入取款金额') def __print_bill(self): print('打印账单') def __take_money(self): print('取款') def withdraw(self): self.__card() self.__auth() self.__input() self.__print_bill() self.__take_money() a=ATM() a.withdraw() 隔离复杂度的例子
property:property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值
python内置方法,遵循了统一访问原则
例子1
class Foo: def __init__(self,val): self.__NAME=val #将所有的数据属性都隐藏起来 @property def name(self): return self.__NAME #obj.name访问的是self.__NAME(这也是真实值的存放位置) @name.setter def name(self,value): if not isinstance(value,str): #在设定值之前进行类型检查 raise TypeError('%s must be str' %value) self.__NAME=value #通过类型检查后,将值value存放到真实的位置self.__NAME @name.deleter def name(self): raise TypeError('Can not delete') f=Foo('egon') print(f.name) # f.name=10 #抛出异常'TypeError: 10 must be str' del f.name #抛出异常'TypeError: Can not delete'
#类的设计者 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()
绑定与非绑定
绑定给谁,谁来调用就会把它自身作为第一个参数传入
# classmethod 将类绑定 对象也可以但是传入的值仍然是对象 # staticmethod 解除绑定不论被谁调用都不会自动传值 class Anima: @classmethod def eat(self): print(self) pass @staticmethod def run(self): print('from run') pass Anima.eat() cat = Anima() #<class '__main__.Anima'> cat.eat() #<class '__main__.Anima'> Anima.run(123) cat.run(123)

浙公网安备 33010602011771号