概述:
编程范式共有三种,其中两种最重要的编程范式:面向过程编程和面向对象编程,函数式编程
面向过程编程: 就是程序从上到下一步步执行,一步步从上到下,从头到尾的解决问题 ,只是写一些简单的脚本,去做一些一次性任务,用面向过程的方式是极好的,但如果你要处理的任务是复杂的,且需要不断迭代和维护的,那还是用面向对象最方便了。
面向对象编程:OOP编程是利用“类”和“对象”来创建的描述,它可以使程序的维护和扩展变得更简单,并且可以大大提高程序开发效率 ,另外,基于面向对象的程序可以使它人更加容易理解你的代码逻辑,面向对象的几个核心特性如下:
1.Class 类
一个类即是对一类拥有相同属性的对象的抽象、原型。在类中定义了这些对象的都具备的属性(variables(data))、共同的方法
2.Object 对象
一个对象即是一个类的实例化后实例,一个类必须经过实例化后方可在程序中调用,一个类可以实例化多个对象,每个对象亦可以有不同的属性,就像人类是指所有人,每个人是指具体的对象,人与人之前有共性,亦有不同
3.封装
在类中对数据的赋值、内部调用对外部用户是透明的,这使类变成了一个胶囊或容器,里面包含着类的数据和方法
4.继承
一个类可以派生出子类,在这个父类里定义的属性、方法自动被子类继承
5.多态
多态是面向对象的重要特性,简单点说:“一个接口,多种实现”,指一个基类中派生出了不同的子类,且每个子类在继承了同样的方法名的同时又对父类的方法做了不同的实现,这就是同一种事物表现出的多种形态,多态允许将子类的对象当作父类的对象使用,某父类型的引用指向其子类型的对象,调用的方法是该子类型的方法。
这里引用和调用方法的代码编译前就已经决定了,而引用所指向的对象可以在运行期间动态绑定
优点:OOP可以使程序更加容易扩展和易更改。
任何编程,我们都要明确记住以下原则:
写重复代码是非常不好的低级行为
你写的代码需要经常变更
代码总是需要不断的更改,不是修改bug就是添加新功能等,所以为了日后方便程序的修改及扩展,代码一定要遵循易读、易改的原则(专业数据叫可读性好、易扩展)。
函数的出现就轻松的解决重复代码的问题,对于需要重复调用的功能,只需要把它写成一个函数,然后在程序的各个地方直接调用这个函数名就好了,并且当需要修改这个功能时,只需改函数代码,然后整个程序就都更新了。
C#、Java只能用面向对象编程。Ruby、Python是可以用函数编程和面向对象。
- 面向过程编程:根据业务逻辑从上到下写代码
- 函数式编程:讲某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可
- 面向对象编程:对函数进行分类和封装
面向过程编程:初学者最容易接受
while True: if cpu利用率 > 90%: #发送邮件提醒 连接邮箱服务器 发送邮件 关闭连接 if 硬盘使用空间 > 90%: #发送邮件提醒 连接邮箱服务器 发送邮件 关闭连接 if 内存占用 > 80%: #发送邮件提醒 连接邮箱服务器 发送邮件 关闭连接
函数式编程:增强代码的重用性和可读性:
def 发送邮件(内容) #发送邮件提醒 连接邮箱服务器 发送邮件 关闭连接 while True: if cpu利用率 > 90%: 发送邮件('CPU报警') if 硬盘使用空间 > 90%: 发送邮件('硬盘报警') if 内存占用 > 80%: 发送邮件('内存报警')
面向对象编程:是一种编程方式,需要使用“类”和“对象”来实现,所以,面向对象编程其实就是对“类”和“对象”的使用。
面向对象不是所有情况都适用
类就是一个模板,模板里可以包含多个函数,函数里实现一些功能
对象则是根据模板创建的实例,通过实例对象可以执行类中的函数,创建对象==创建实例
注:
- class是关键字,表示类
- 创建对象,在类名称后加括号即可
- 类中定义的函数叫做“方法”
class Foo: def Bar(self): print("Bar") def Hello(self): print("Hello") obj = Foo() obj.Bar() obj.Hello()
函数式编程:直接执行函数
面向对象编程:创建对象 通过对象执行方法
def 如果写在外面称为函数, 如果写在class 里面称为方法(可以理解为类封装了函数)
面向对象三大特性
面向对象的三大特性:封装、继承、多态
-
封装
封装,将内容封装到某个地方,以后再去调用被封装在某处的内容。所有在使用面向对象的封装特性时,需要:
使用场景:
1、当同一类型的方法具有相同参数时,直接封装到对象即可。
2、把类当做模板,创建多个对象(对象内封装的数据可以不一样)
第一步:将内容封装到某处
__init__:构造方法, 创建对象的时候自动调用, >>>初始化
__del__:析构方法, 解释器销毁对象时候自动调用,通常用于执行一些收尾工作,如关闭数据库链接,打开临时文件.
class Foo: #####称为构造方法,根据类创建对象时自动执行 def __init__(self,name): self.Name = name def eat(self): print(self.Name + "eat") def sleep(self): print(self.Name + "sleep") #根据类Foo创建对象(或创建一个Foo类的实例) #自动执行Foo类的__init__方法 obj1 = Foo("zc") #根据类Foo创建对象(或创建一个Foo类的实例) #自动执行Foo类的__init__方法 obj2 = Foo("zc1") obj1.eat() obj2.sleep() #打印结果: # zceat # zc1sleep
self是一个形式参数,执行方法的对象,谁执行它它就代表谁:当执行 obj1 = Foo("zou")时,self等于 obj1
当执行 obj2 = Foo("zhang")时,self等于 obj2
所以,内容其实被封装到了对象 obj1 和 obj2 中,每个对象中都有name属性
第二步:从某处调用被封装的内容
调用被封装的内容时,有两种情况:
1、通过对象直接调用被封装的内容
class Foo: def __init__(self,name,age): self.Name = name self.Age = age def eat(self): print(self.Name + "eat") def sleep(self): print(self.Name + "sleep") obj1 = Foo("zc",18 )#根据类Foo创建对象, #自动执行Foo类的__init__方法 #直接调用obj1对象的属性 print(obj1.Name) print(obj1.Age) obj2 = Foo("zc",19)#根据类Foo创建对象, #自动执行Foo类的__init__方法 #直接调用obj2对象的属性 print(obj2.Name) print(obj2.Age) # #打印结果: # zc # 18 # zc # 19
2、通过self间接调用被封装的内容
class Foo: def __init__(self,name,age): self.Name = name self.Age = age def f(self): print(self.Name) print(self.Age) obj1 = Foo("zc",18) obj1.f() # Python默认将obj1传给self参数,即:obj1.f(obj1),所以,此时方法内部的 self = obj1,即:self.name 是 zou ;self.age 是 18 obj2 = Foo("zc",19) obj2.f() # Python默认将obj2传给self参数,即:obj2.f(obj2),所以,此时方法内部的 self = obj2,即:self.name 是 zhang ;self.age 是 19
总结:对于面向对象的封装来说,其实就是使用构造方法将内容封装到对象中,然后通过对象直接或者self间接获取被封装的内容。
class Person: def __init__(self,name,age,weight): #普通字段(保存在对象里面) self.NAME = name self.AGE = age self.Weight = weight def chi(self): self.Weight = self.Weight + 2 # print(self.Weight) print('%s 吃' % self.NAME, self.Weight) def jianshen(self): self.Weight = self.Weight - 1 # print(self.Weight) print('%s 健身' % self.NAME, self.Weight) ret = Person('zc',29,120) ret.chi() ret.jianshen() ret1 = Person('zc1',30,125) ret1.chi() ret1.jianshen()
练习:在终端输出如下信息
小明,10岁,男,上山去砍柴
小明,10岁,男,开车去东北
老李,90岁,男,上山去砍柴
老李,90岁,男,开车去东北
def kanchai(name, age, gender): print "%s,%s岁,%s,上山去砍柴" %(name, age, gender) def qudongbei(name, age, gender): print "%s,%s岁,%s,开车去东北" %(name, age, gender) kanchai('小明', 10, '男') qudongbei('小明', 10, '男') kanchai('老李', 90, '男') qudongbei('老李', 90, '男')
class Foo: def __init__(self, name, age ,gender): self.name = name self.age = age self.gender = gender def kanchai(self): print "%s,%s岁,%s,上山去砍柴" %(self.name, self.age, self.gender) def qudongbei(self): print "%s,%s岁,%s,开车去东北" %(self.name, self.age, self.gender) xiaoming = Foo('小明', 10, '男') xiaoming.kanchai() xiaoming.qudongbei() laoli = Foo('老李', 90, '男') laoli.kanchai() laoli.qudongbei()
如果使用函数式编程,需要在每次执行函数时传入相同的参数,如果参数多的话,又需要粘贴复制了...
而对于面向对象只需要在创建对象时,将所有需要的参数封装到当前对象中,之后再次使用时,通过self间接去当前对象中取值即可
-
继承
继承:面向对象中的继承和现实生活中的继承相同,即:子可以继承父的内容。
例如:
动物共同功能:吃、喝、
猫特有功能:喵喵叫
狗特有功能:汪汪叫
class zhaowu: def zw(self): print(self.name + '生万物') class Animals(zhaowu): def chi(self): print(self.name + '吃') def he(self): print(self.name + '喝') class Dog(Animals): def __init__(self,name): self.name = name def jiao(self): print(self.name + '汪') zc = Dog('张1 ') zc.zw() zc.chi() zc.he() zc.jiao() #打印结果: #张1 生万物 #张1 吃 #张1 喝 #张1 汪
对于面向对象的继承来说,就是将多个类共有的方法提取到父类(基类)中,子类(派生类)仅需继承父类(基类)而不必一一实现每个方法。
注:
派生类可以继承基类中所有的功能
派生类和基类某一方法同时存在,优先找派生类
class zhaowu: def zw(self): print(self.name + '生万物') class Animals(zhaowu): def chi(self): print(self.name + '吃') def he(self): print(self.name + '喝') def sleep(self): print(self.name + '不爱睡觉') class Dog(Animals): def __init__(self,name): self.name = name def jiao(self): print(self.name + '汪') def sleep(self): print(self.name + '爱睡觉')#优先执行它 zc = Dog('张1 ') zc.zw() zc.chi() zc.he() zc.jiao() zc.sleep() # 打印结果 # 张1 生万物 # 张1 吃 # 张1 喝 # 张1 汪 # 张1 爱睡觉
class zhaowu: def zw(self): print(self.name + '生万物') def he(self): print(self.name + '喝') def sleep(self): print(self.name + '爱睡觉') class Animals: def chi(self): print(self.name + '吃') def he(self): print(self.name + '喝') def sleep(self): print(self.name + '不爱睡觉') class Dog(zhaowu,Animals): def __init__(self,name): self.name = name def jiao(self): print(self.name + '汪') # def sleep(self): # print(self.name + '爱睡觉') zc = Dog('张1 ') zc.zw() zc.chi() zc.he() zc.jiao() zc.sleep() #d打印结果 # 张1 生万物 # 张1 吃 # 张1 喝 # 张1 汪 # 张1 爱睡觉
Python类可以继承多个类,Java和C#中则只能继承一个类
Python类如果继承了多个类,那么寻找方法的方式(先自己派生类>左边基类>右边基类)后又分两种(Python3中)
第一种:
class A: def f1(self): print("A") class B: def f1(self): print("B") class C(A): def f1(self): print("C") class D(B): def f1(self): print("D") class E(C, D): def f1(self): print("E") obj = E() obj.f() #查找顺序:E-->C-->A-->D-->B
第二种:
class AQ(): def f(self): print("AQ") class A(AQ): def f1(self): print("A") class B(AQ): def f1(self): print("B") class C(A): def f1(self): print("C") class D(B): def f1(self): print("D") class E(C, D): def f1(self): print("E") obj = E() obj.f() # 查找顺序:E-C-A-D-B-AQ
-
多态
Python不支持多态并且也用不到多态,多态的概念是应用于C#和Java这一类强类型语言中,而Python崇尚“鸭子类型”。
鸭子类型:
class 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)
#打印
#S1.show
#None
#S2.show
#None
实例变量与类变量
类变量:
是可在类的所有实例之间共享的值(也就是说,它们不是单独分配给每个实例的)大家共用的属性,写一个就行,可以节省内存
实例变量:
而实例变量则属对象私有,某一个对象将其值改变,不影响其他对象;实例变量(静态属性),作用域就是实例本身
私有方法:
通过给方法前面加双下划线为私有方法,外面不能访问, 只能自己访问
私有属性(变量):
通过在属性变量名前加上双下划线定义属性为私有属性,访问可以通过在类中声明普通方法,返回私有类形变量的方式获取
代码: class Role(object):#类名,当一个类里面有实例变量又有类变量,先打印实例变量, (object)是新式类的写法,必须这样写 n = 123#类变量 n_list=[] def __init__(self, name, role, weapon, life_value=100, money=15000):#初始化函数,在生成一个角色时要初始化的一些属性就填写在这里 #__init__构造函数:在实例化时做一些类的初始化的工作,给下面实例赋名字 self.name = name#等于r1.name=name, self.name变量赋给了实例叫做:实例变量(静态属性),作用域就是实例本身 self.role = role self.weapon = weapon self.__life_value = life_value#私有属性(__life_value) self.money = money def __del__(self):#析构函数 print("%s 彻底死掉。。。"% self.name)#程序退出后最后执行 def show_status(self):#私有属性写到方法里面,调用方法 print('name:%s weapon:%s life_val:%s'%(self.name,self.weapon,self.__life_value)) def shot(self):#类的方法,功能(执行的过程叫动态属性) print("shooting...") def got_shot(self): self.__life_value -=50 print("%s:ah...,I got shot..."% self.name) def buy_gun(self, gun_name): print("%s just bought %s" % (self.name,gun_name)) print(Role.n) r1 = Role('Alex', 'police', 'AK47') #Role(r1,'Alex', 'police', 'AK47')把一个类变成一个具体对象的过程叫实例化(初始化一个类,相当于造了一个对象) #实例化完成后生成一个r1对象,又叫做Role这个类的实例 r1.name='zc'#修改值 r1.n_list.append('from r1')#共用同一个n_list内存变量 r1.bullet_prove=True#给实例增加新的属性 r1.n='修改类变量'#改类变量(实际是在我的内存里创建了新的变量,不影响原类变量) print(r1.n,r1.name,r1.bullet_prove) print(r1.weapon) #del r1.weapon#删除值 r1.got_shot() print(r1.show_status()) r2 = Role('Jack', 'terrorist', 'B22',r1.weapon) #生成一个角色 r2.name='zcok168'#修改值 r2.n_list.append('from r2')#共用同一个n_list内存变量 print(r2.n,r2.name,r2.n_list) Role.n='abc' print(Role.n_list)#共用同一个n_list内存变量 print(r1.n,r2.n) r1.buy_gun('AK47') 继承 继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。 class People:#经典类 #class People(object):新式类,在继承方式上有变化 def __init__(self,name,age,): self.name=name self.age=age def eat(self): print('%s is esting...'% self.name) def sleep(self): print('%s is sleeping...'% self.name) def talk(self): print('%s is taling...' % self.name) class Relation(object):#多继承写法 def make_friends(self,obj): print('%s is making frienda with %s'%(self.name,obj.name)) class Man(People,Relation):#子类,继承People def __init__(self,name,age,money):#构造函数进行重构,父类的所有参数需重写一遍,增加一个新的功能money People.__init__(self,name,age)#经典类写法:需要先执行父类方法。新式类写法(意思相同):super内置方法,super(Man, self).__init__(name,age) self.money =money#新加参数 print('%s 一出生就有%s money' % (self.name,self.money))#新加参数 def piao(self): print('%s is piaoing..'% self.name) def sleep(self):#子类的方法和父类的方法一样时会覆盖父类方法 People.sleep(self)#重构父类方法,直接调用了父类方法 print(' is sleeping..') class Woman(People,Relation): def get_birth(self): print('%s is born a boby..'% self.name) m1=Man('zc',20,100) m1.eat() m1.piao() m1.sleep() w1=Woman('VV',22) w1.get_birth() # w1.piao() m1.make_friends(w1) 经典类新式类的继承顺序 Py2经典类是按深度优先来继承的,新式类是按广度优先来继承的 Py3 经典类和新式类都是按广度优先来继承的 class A: def __init__(self): print('A') class B(A): def __init__(self): print('B') class C(A): def __init__(self): print('C') class D(B,C): def __init__(self): print('D')