Python之路【第四篇补充】:面向对象初识和总结回顾
面向过程的编程
面向过程:根据业务逻辑从上到下写垒代码!
例子:
需求一、有一个程序需要做身份认证:
用户名有个字典: #定义一个用户名信息字典 user_info = { "zhangsan":"mima1", "lisi":"mima2", "wangwu":"mima3", } 现在做登录判断: user_input = raw_input("\033[32;1m请输入您的用户名:\033[0m") #获取用户的用户名 pass_input = raw_input("\033[32;1m请输入您的密码:\033[0m")#获取用户输入的密码 if user_info.get(user_input): #判断用户名是否存在,如果存在判断密码是否正确! if pass_input == user_info[user_input]: #判断用户输入的密码和存储的用户密码是否匹配 print "\033[32;1m登录成功\033[0m" else: print "\033[31;1m密码错误\033[0m" else: print "\033[31;1m您输入的用户名不存在\033[0m" #用户不存在用户(如果用户不存在返回None)
现在又有一个程序需要做登录认证了怎么办? 好吧只能在把代码复制过来一遍! user_info = { "zhangsan":"mima1", "lisi":"mima2", "wangwu":"mima3", } 现在做登录判断: user_input = raw_input("\033[32;1m请输入您的用户名:\033[0m") #获取用户的用户名 pass_input = raw_input("\033[32;1m请输入您的密码:\033[0m")#获取用户输入的密码 if user_info.get(user_input): #判断用户名是否存在,如果存在判断密码是否正确! if pass_input == user_info[user_input] #判断用户输入的密码和存储的用户密码是否匹配 print "\033[32;1m登录成功\033[0m" else: print "\033[31;1m密码错误\033[0m" else: print "\033[31;1m您输入的用户名不存在\033[0m" #用户不存在用户(如果用户不存在返回None) 如果有N个程序需要调用这个认证呢?难道每次都要粘贴复制?好吧可以复制,但问题来了我又有一个要求!我想在这里面在加一个 登录次数的判断,如果输入错误3次锁定怎么办?所有代码都需要改对吧!
现在面向过程的编程弊端体现出来了:每次调用的时候都的重写,代码特别长,代码重用性没有,每次增加新功能所有的代码都的修改!
那有什么办法解决上面出现的弊端呢?函数就出现了!!!
面向函数编程
面向函数:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可!
函数解释:
函数可以理解为一个一个的功能块,你把一个大的功能拆分成一块一块的,用某项功能的时候就去调用某个功能块即可!
函数可以理解为:乐高积木,给你一块一块的,你可以用这些积木块组成你想要的任何,功能!
函数可以调用函数!主函数的作用就是把函数进行串联、调用!函数本身是不能自己执行的如果你不调用就永不执行!
例子: 同样的需求: 有一个程序需要做身份认证: user_info = { "zhangsan":"mima1", "lisi":"mima2", "wangwu":"mima3", } def login_auth(): #定义一个函数 user_input = raw_input("\033[32;1m请输入您的用户名:\033[0m") #获取用户的用户名 pass_input = raw_input("\033[32;1m请输入您的密码:\033[0m")#获取用户输入的密码 if user_info.get(user_input): #判断用户名是否存在,如果存在判断密码是否正确! if pass_input == user_info[user_input] #判断用户输入的密码和存储的用户密码是否匹配 print "\033[32;1m登录成功\033[0m" else: print "\033[31;1m密码错误\033[0m" else: print "\033[31;1m您输入的用户名不存在\033[0m" #用户不存在用户(如果用户不存在返回None) login_auth() #调用函数 现在有N个程序需要调用我的模块怎么办,非常简单!比如我这个loging()是一个独立的文件(模块)如下:
很简单就调用了,每次在做认证的时候就直接调用下函数就可以了!那我想增加新功能怎么办呢?直接在函数里修改加上3次密码锁定即可。对于调用他的其他程序来说他并不知道你增加密码了。
面向函数的编程优点:重用性强、缩减了代码长度、可扩展性强!
总结:可以理解为,函数把面向过程进行了一次封装。把那些固定功能的药水放在一个杯子里,每次要使用药水的时候,不用直接在去拿药水,直接拿盛药水的杯子即可。如下图
装饰器:
装饰器是函数,只不过该函数可以具有特殊的含义,装饰器用来装饰函数或类,使用装饰器可以在函数执行前和执行后添加相应操作。
简单的来说在不修改原函数的情况下,在对原函数进行包装!
现在需求来了!我有好多程序需要给他增加认证程序:func1、func2、func3、func4........
#!/usr/bin/env python #-*- coding:utf-8 -*- user_info = { "zhangsan":"mima1", "lisi":"mima2", "wangwu":"mima3", } def login_auth(): #定义一个函数 user_input = raw_input("\033[32;1m请输入您的用户名:\033[0m") #获取用户的用户名 pass_input = raw_input("\033[32;1m请输入您的密码:\033[0m")#获取用户输入的密码 if user_info.get(user_input): #判断用户名是否存在,如果存在判断密码是否正确! if pass_input == user_info[user_input]: #判断用户输入的密码和存储的用户密码是否匹配 print "\033[32;1m登录成功\033[0m" else: print "\033[31;1m密码错误\033[0m" else: print "\033[31;1m您输入的用户名不存在\033[0m" #用户不存在用户(如果用户不存在返回None) login_auth() #调用函数 def func1(): print "hello This is Func1" def func2(): print "hello This is Func2" def func3(): print "hello This is Func3" def func4(): print "hello This is Func4"
解决方法1:修改原来func1代码把login_auth()加入到代码中!(很low)
开发封闭原则:写代码要遵循开发封闭原则,虽然在这个原则是用的面向对象开发,但是也适用于函数式编程,简单来说,它规定已经实现的功能代码不允许被修改,但可以被扩展,即:
- 封闭:已实现的功能代码块
- 开放:对扩展开发
解决方法2:使用装饰器!
#!/usr/bin/env python #-*- coding:utf-8 -*- user_info = { "zhangsan":"mima1", "lisi":"mima2", "wangwu":"mima3", } def login_auth(): #定义一个函数 user_input = raw_input("\033[32;1m请输入您的用户名:\033[0m") #获取用户的用户名 pass_input = raw_input("\033[32;1m请输入您的密码:\033[0m")#获取用户输入的密码 if user_info.get(user_input): #判断用户名是否存在,如果存在判断密码是否正确! if pass_input == user_info[user_input]: #判断用户输入的密码和存储的用户密码是否匹配 return True else: return False else: return False def wrapper(func): def inner(): if login_auth(): #如果登录成功回返回True然后执行func函数(func=被装饰的函数) func() else: return "\033[32;1m登录失败\033[0m" return inner @wrapper def func1(): print "hello This is Func1" @wrapper def func2(): print "hello This is Func2" @wrapper def func3(): print "hello This is Func3" @wrapper def func4(): print "hello This is Func4" func1() #func2() #func3() #func4()
面向对象编程
之前说了函数的作用是就是了方便重用和扩展,其实如果没有面向对象,要实现某个功能用函数也是可以的!
比如C他就没有面向对象但是他照样可以写出Linux这么NB的系统。
好了,那说下为要有面向对象!其实面向对象很简单:他就是使代码更容易的重用,更容易的扩展!
面向对象名词解释:Object Oriented Programming 就如上面说的他是程序的一种设计方法范型。
ps:面向对象就相当于把函数进行了一次封装,并且进行了优化!(非的要用封装来表述的话我觉的可以这么理解)
一、什么是类&对象
类:可以理解为他是一个模板,比如人们在说“人”这个名词的时候,没人知道这个“人”具体是指那个人!
对象:对象是一个实际的物体,他有自己的属性和特征、行为的,比如alex和eric,当说到这两个人的时候就会想到,alex很猥琐、eric很闷骚他们的特征、动作啊都能具体的显示出来!
二、封装&实例化&调用
例子(1)
有个程序员叫小月月,他费尽千辛万苦函数写出一个女朋友叫alex,他在写这个alex这个女朋友的时候的指定他能干什么什么属性吧?
特征、长相、吃饭、睡觉、逛街、。。。。。
突然有一天alex跑了,他是不是还的写一个新的女朋友,但是他在写第二eric个女朋友的时候有很多和第一个女朋友相似的比如吃饭、睡觉、逛街、做饭、等。。。。。
这里如果没有面向对象,他也会想怎么去重用代码,面向对象的诞生的由来就出现了!就是是你更容易的重用!
例子(2)
结合上面的例子,你现在有两个函数,指定女朋友做什么例如:
#!/usr/bin/env python #-*- coding:utf-8 -*- def sleep(name): print "The Girl frend %s is sleeping....." % name def eat(name): print "The Girl frend %s is eating....." % name grilfred1sleep = sleep('alex') grilfred2sleep = sleep('eric') grilfred1eat = eat('alex') grilfrend2eat = eat('eric') 查看输出结果: The Girl frend alex is sleeping..... The Girl frend eric is sleeping..... The Girl frend alex is eating..... The Girl frend eric is eating.....
你每次调用的时候你都的告诉他,是谁在调用对吧?如果你不告诉他(不给他传参数)是不是他就不知道是那个女朋友在调用这个函数呢?
好咱们在看下类的定义:
#!/usr/bin/env python #-*- coding:utf-8 -*- class Person(object): #定义一个类Person(object) 这个object是必要参数,语法规定 def __init__(self,name): # '''这个__init__(self,name) 这里__init__是告诉他我这个是初始化函数,当类被调用的时候就自动执行这个函数 看下面的调用(他的学名叫做【实例化】),grilfrend1 = Person('alex'),当你实例化的时候,这个__init__标注的函数 将会被执行! def __init__(self,name): 这个self有什么用呢?看下下面类中的函数调用都的有个self,在看下我上面举得例子函数去做这个操作的时候 ,你在调用函数的时候是不是都的给他个名字呢?才能区分是谁在调用,这个self就是告诉类是谁在调用!name就是用户传过来的参数 ''' self.name = name #这里就相当于grilfrend1.name = alex grilfrend2.name = eric def eat(self): print "The Girl frend %s is eating...." % self.name def sleep(self): print "The Girl frend %s is sleeping...." % self.name grilfrend1 = Person('alex') '''grilfrend1 = Person('alex') 这个操作叫做实例化,什么意思呢,就是把模板实际应用到某个具体的物体上。拿人来举例子 class Person(object) # 你定义的这个类,在没有实例化之前是没有意义的他仅仅是一个模板,当进行实例化之后,grilfrend1 = Person('alex')#实例化 grilfrend1 = Person('alex') 才有意义,现在grilfrend1才是一个真正意义上的人(对象)。 ''' grilfrend2 = Person('eric') grilfrend1.eat() '''在看下这里的调用类中的方法grilfrend1.eat() 我还需要告诉他是谁来调用的吗?不需要了,因为grilfrend1已经是一个人了,并且他有自己的名子,动作 我在调用的时候只需要告诉他要做什么动作就可以了,这些东西都封装在类里,直接调用就可以! grilfrend2 = Person('alxe') 也已经实例化了,你说在调用他的时候还需要指定名字吗?这个就是slef的存在的意义,实例化之后你在调用的时候就是通过这个人(对象)去调用,想想一下如果没有这个slef 在类中,你还的让用户传入参数,那咱们还用这个类有什么用呢? grilfrend2.eat() 你实例化之后你在调用的时候就相当于Person.eat(grilfrend1) '''
注:很容易发现,有了这个类在重新调用的时候是不是省去了在重新输入特定的参数!
#!/usr/bin/env python #-*- coding:utf-8 -*- class Person(object): #定义一个类Person(object) 这个object是必要参数,语法规定 def __init__(self,name,age): self.name = name #这里就相当于grilfrend1.name = alex grilfrend2.name = eric self.age = age def eat(self): print "The Girl frend %s is eating...." % self.name def sleep(self): print "The Girl frend %s is sleeping...." % self.name def age_now(self): print "%s ,I am %d year old" % (self.name,self.age) grilfrend1 = Person('alex',18) #实例化输入相关的参数 grilfrend2 = Person('alxe',19) #实例化输入先关的参数 grilfrend1.eat() grilfrend1.age_now() #调用的时候直接调用类的方法即可!
图解:
所以我们以后在写程序的时候不是要写某一个人出来了,而是要抽象,然后在造的时候,一造一大片!!!
静态方法:
比如现在我有一个工具类,每次调用的时候我仅想调用里面的方法!如果每次调用这个类都需要实例化,的话比如成千上完的人去掉用,都给他进行实例化,那么是不是很占用内存?
有什么办法调用的时候不需要实例化呢?直接调用类中的方法呢?静态方法
class Tools(object): @staticmethod #设置为静态方法!装饰器 def hatchet(): print "axe someting....." @staticmethod #设置为静态方法!装饰器 def saw(): print "saw someting....." Tools.hatchet() #这里调用的时候就不用实例化了!(工具类)
私有属性:
#!/usr/bin/env python #-*- coding:utf-8 -*- class Game(object): def __init__(self): self.__name = "shuaige"# 定义私有属性 self.age = 19 # 普通属性定义 gamer1 = Game() # 正常输出 print gamer1.age # 提示找不到属性 print gamer1.__name ''' 结果: 19 Traceback (most recent call last): File "E:/ѧϰ/GitHub/homework/tianshuai/privately-owned.py", line 16, in <module> print gamer1.__name AttributeError: 'Game' object has no attribute '__name' ''' class Game(object): def __init__(self): self.__name = "shuaige"# 定义私有属性 self.age = 19 # 普通属性定义 gamer1 = Game() # 正常输出 print gamer1.age gamer1.__name = 'shuaige' #只能这么调用私有属性 print gamer1.__name #并且要注意,就算类继承也是无法调用私有属性的! #! encoding=UTF-8 class Game(object): def __init__(self): self.__name = "shuaige"# 定义私有属性 self.age = 19 # 普通属性定义 class Newgame(Game): def say_name(self): print self.__name gamer2 = Newgame() gamer2.say_name() #总结:私有属性,仅是类中自己调用的,外面是无法调用他的!
三、继承
经过小月月和他女朋友的努力他们有了自己的孩子,然后要为孩子创建一个类,想想以后他们还会有很多孩子,我们想象一下孩子的类和人这个类是不是有很多相同的地方?
比如睡觉、吃、年龄?难道在需要重新写下类吗?不用在python中有个继承的方法!
#!/usrbin/env python #-*- coding:utf-8 -*- class Person(object): #定义一个类Person(object) 这个object是必要参数,语法规定 def __init__(self,name,age): self.name = name #这里就相当于grilfrend1.name = alex grilfrend2.name = eric self.age = age def eat(self): print "The Girl frend %s is eating...." % self.name def sleep(self): print "The Girl frend %s is sleeping...." % self.name def age_now(self): print "%s ,I am %d year old" % (self.name,self.age) class Child(Person): def cute(self): print "TH child %s is very cute" % self.name #"这里看下在在初始函数里没有指定但是我还是可以调用父类中的初始化参数" child1 = Child('xiaoxiaoyueyue',2) #实例化 child1.eat() #这里看下,我在Child的类中并没有指定吃的方法,但是我继承了父类中的方法所以就不需要在写一次了
抽象类和方法
#!/usr/bin/env python #-*- coding:utf-8 -*- from abc import ABCMeta,abstractmethod #调用抽象方法 ''' 现在我有这么一个需求,我现在是公司的CTO,我站在架构的角度,我要写一个大型程序。我分了好模块,我对每个模块进行了类的划分 每个类了,都规定了都具备那些方法,都定义出来了,我只是把方法定义出来了,方法里的具体实现还需要我去具体实现吗?直接让下面的人 去做就可以了,具体的函数让他们去实现。 ''' class Car(object): def __init__(self,color,brand): self.color = color self.brand = brand def start(self): print "staring the car" ###################################################################################################################### ''' 看上面的类,手下的人写一个BMW如果要使用我写的类,有办法强制让他按照我写的方法写吗?比如我有个start发放,你有办法控制吗? 不可以的! ''' class Bmw(Car): #继承父类 def __init__(self,color,brand): self.color = color self.brand = brand def notstart(self): print "you cant contrl myself" car1 = Bmw('rad','bmw') car1.notstart() ''' 这里可以看到,我父类定义的东西,员工在调用的时候没有强制的约定我可以实现父类的start也可以不实现?但是现在要求,CTO定义的方法 其他人在调用的时候必须实现这个方法怎么办? 使用抽象类和抽象方法!什么意思,就是我定义好了这个类和方法,方法里是可以没有内容的。 看下面的代码,我在抽象方法里,可以没有内容,但是我定义了,其他人在调用我的时候必须实现这个方法 '''
总结:抽象类和抽象方法就是为了实现咱们上述所说的要求,我在上层模板中定义了一个模板,下面的人在调用的时候必须实现,我上层定义的抽象方法!
更多请参考:http://www.cnblogs.com/wupeiqi