day 21
一、面向对象概述
1、什么是面向对象:
1、面向过程的程序设计:
面向过程,核心是过程,即解决问题的步骤,编写程序好比在设计一条流水线,为了得到合格的产品(程序),人为指定程序需要翔安什么再干什么。它是一种机械式的思维方式。
优点:将复杂的问题流程化,进而简单化(将一个复杂的问题,拆分成一个个小的问题去实现,实现小的步骤就会变得比较简单。)
缺点:可扩展性差(解决问题的指向性比较强,若需求有所变动,修改幅度较大)
使用场景:对扩展性要求较低的软件,比如系统内核,脚本程序(运维工程师写的程序,其目的就是安装一堆软件),Apache HTTP服务器等; 当我们要开发的程序需非常高的扩展性时就不能再使用该方式了
2、面向对象的程序设计:
面向对象:核心为对象二字,对象即特征与技能的结合体,基于面向对象的程序设计就好比在创造一个世界,而编写程序的人就相当于是这个世界的上帝,存在的一切皆为对象,不存在的也可以被创造出来,与面向过程机械的思维方式形成鲜明的对比,面向对象更加注重对现实世界的模拟,是一种“上帝式”的思维方式。
优点:a、可扩展性强(对某一个对象的单独修改,会立刻反映到整个体系中,例如在游戏中对人物参数特性和技能的修改都会变得很容易。);
b、各个对象之间的耦合度较低,当其中一个对象出现了问题,不会对其他对象产生影响。
缺点:a、编程的复杂程度高于面向过程;
b、无法预知执行结果。
使用场景:需要较高的可扩展性时使用(直接与用户发生交互的程序,如qq,微信);对不需要较高扩展性的程序而言,使用面向对象反而增加了复杂度。
2、为什么要使用面向对象:
在开发一些需要与用户直接打交道的程序时,因用户的需求是不停的发生变化,所以我们要使用可扩展性较高的面向对象式编程(本质就是使用不同的对象来编写程序)方式来编写程序。
二、类与对象:
1、类:
类十一个抽象的概念,类即种类、类别,是面向对象设计的重要概念,是一系列的对象的相同特征和技能的结合体。
注:现实世界中是先有对象,再有类的概念。
程序中是先定义类,然后在通过调用类来产生对象。
2、对象:
对象是通过调用类来产生获得的,因此调用类的过程又称为类实例化的过程。调用类会得到一个返回值,该返回值就是类的一个具体存在的对象(实例)。
#在程序中,务必保证:先定义(类),后使用(产生对象) PS: 1. 在程序中特征用变量标识,技能(方法)用函数标识 2. 因而类中最常见的无非是:变量(特征)和函数(方法)的定义 #程序中的类 class OldboyStudent: school='oldboy' def learn(self): print('is learning') def eat(self): print('is eating') def sleep(self): print('is sleeping') #注意: 1.类中可以有任意python代码,这些代码(函数体类的代码仍然存放在内存中,调用时才会执行)在类定义阶段便会执行 2.因而会产生新的名称空间,用来存放类的变量名与函数名,可以通过OldboyStudent.__dict__查看 3.对于经典类来说我们可以通过该字典操作类名称空间的名字(新式类有限制),但python为我们提供专门的.语法 4.点是访问属性的语法,类中定义的名字,都是类的属性 5.类本省就是一个容器类型(名称空间),用来存放名字,这是类的用途之一。 #程序中类的用法 .:专门用来访问属性,本质操作的就是__dict__ OldboyStudent.school #等于经典类的操作OldboyStudent.__dict__['school'] OldboyStudent.school='Oldboy' #等于经典类的操作OldboyStudent.__dict__['school']='Oldboy' OldboyStudent.x=1 #等于经典类的操作OldboyStudent.__dict__['x']=1 del OldboyStudent.x #等于经典类的操作OldboyStudent.__dict__.pop('x') #程序中的对象 #调用类,或称为实例化,得到对象 s1=OldboyStudent() s2=OldboyStudent() s3=OldboyStudent() #如此,s1、s2、s3都一样了,而这三者除了相似的属性之外还各种不同的属性,这就用到了__init__ #注意:该方法是在对象产生之后才会执行,只用来为对象进行初始化操作,可以有任意代码,但一定不能有返回值 class OldboyStudent: ...... def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex ...... s1=OldboyStudent('李坦克','男',18) #先调用类产生空对象s1,然后调用OldboyStudent.__init__(s1,'李坦克','男',18) s2=OldboyStudent('王大炮','女',38) s3=OldboyStudent('牛榴弹','男',78) #程序中对象的用法 #执行__init__,s1.name='牛榴弹',很明显也会产生对象的名称空间 s2.__dict__ {'name': '王大炮', 'age': '女', 'sex': 38} s2.name #s2.__dict__['name'] s2.name='王三炮' #s2.__dict__['name']='王三炮' s2.course='python' #s2.__dict__['course']='python' del s2.course #s2.__dict__.pop('course')
三、属性查找:
类的两种属性分别为数据属性和函数属性
1、类的数据属性:所有对象共享
2、类的函数属性:绑定给对象使用
注:属性查找的顺序:obj对象产生后自己会生成一块新的内存空间,obj需要调用属性是首先会先从自己的空间中进行查找,如果找不到就会到类的空间中去找,如果找不到就会到父类的空间中去找....最后找不到抛出异常。
#类的数据属性是所有对象共享的,id都一样 print(id(OldboyStudent.school)) print(id(s1.school)) print(id(s2.school)) print(id(s3.school)) ''' 4377347328 4377347328 4377347328 4377347328 ''' #类的函数属性是绑定给对象使用的,obj.method称为绑定方法,内存地址都是不一样 #ps:id是python的实现机制,并不能真实反映内存地址,如果有内存地址,还是以内存地址为准 print(OldboyStudent.learn) #0x1021329d8 print(s1.learn) #0x1021466d8 print(s2.learn) #0x102146710 print(s3.learn) #0x102146748 ''' <function OldboyStudent.learn at 0x1021329d8> <bound method OldboyStudent.learn of <__main__.OldboyStudent object at 0x1021466d8>> <bound method OldboyStudent.learn of <__main__.OldboyStudent object at 0x102146710>> <bound method OldboyStudent.learn of <__main__.OldboyStudent object at 0x102146748>> '''
四、类中的初始化函数
__ init__函数用于初始化对象,它会在对象刚被创建时自动执行,并传入调用时传递的参数,第一个参数表示要初始化的对象本身。
注:调用类时发生的两件事:
a、创建一个空对象stu;
b、自动触发类中的init功能的执行,并将空对象stu和调用类似括号中传入的参数一同传入。
#方式一、为对象初始化自己独有的特征 class People: country='China' x=1 def run(self): print('----->', self) # 实例化出三个空对象 obj1=People() obj2=People() obj3=People() # 为对象定制自己独有的特征 obj1.name='egon' obj1.age=18 obj1.sex='male' obj2.name='lxx' obj2.age=38 obj2.sex='female' obj3.name='alex' obj3.age=38 obj3.sex='female' # print(obj1.__dict__) # print(obj2.__dict__) # print(obj3.__dict__) # print(People.__dict__) #方式二、为对象初始化自己独有的特征 class People: country='China' x=1 def run(self): print('----->', self) # 实例化出三个空对象 obj1=People() obj2=People() obj3=People() # 为对象定制自己独有的特征 def chu_shi_hua(obj, x, y, z): #obj=obj1,x='egon',y=18,z='male' obj.name = x obj.age = y obj.sex = z chu_shi_hua(obj1,'egon',18,'male') chu_shi_hua(obj2,'lxx',38,'female') chu_shi_hua(obj3,'alex',38,'female') #方式三、为对象初始化自己独有的特征 class People: country='China' x=1 def chu_shi_hua(obj, x, y, z): #obj=obj1,x='egon',y=18,z='male' obj.name = x obj.age = y obj.sex = z def run(self): print('----->', self) obj1=People() # print(People.chu_shi_hua) People.chu_shi_hua(obj1,'egon',18,'male') obj2=People() People.chu_shi_hua(obj2,'lxx',38,'female') obj3=People() People.chu_shi_hua(obj3,'alex',38,'female') # 方式四、为对象初始化自己独有的特征 class People: country='China' x=1 def __init__(obj, x, y, z): #obj=obj1,x='egon',y=18,z='male' obj.name = x obj.age = y obj.sex = z def run(self): print('----->', self) obj1=People('egon',18,'male') #People.__init__(obj1,'egon',18,'male') obj2=People('lxx',38,'female') #People.__init__(obj2,'lxx',38,'female') obj3=People('alex',38,'female') #People.__init__(obj3,'alex',38,'female') # __init__方法 # 强调: # 1、该方法内可以有任意的python代码 # 2、一定不能有返回值 class People: country='China' x=1 def __init__(obj, name, age, sex): #obj=obj1,x='egon',y=18,z='male' # if type(name) is not str: # raise TypeError('名字必须是字符串类型') obj.name = name obj.age = age obj.sex = sex def run(self): print('----->', self) # obj1=People('egon',18,'male') obj1=People(3537,18,'male') # print(obj1.run) # obj1.run() #People.run(obj1) # print(People.run) !!!__init__方法之为对象定制自己独有的特征
五、给对象绑定方法:
1、绑定方法:
绑定方法即将对象与函数方法绑定到一起(通过将对象本身传入函数来进行绑定),此后调用函数就变成了调用对象的方法。
注:当用对象来调用类中的方法时,默认会将对象传入函数方法中,
而用类名来调用时,则需要手动传入对象。
#改写 class OldboyStudent: school='oldboy' def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex def learn(self): print('%s is learning' %self.name) #新增self.name def eat(self): print('%s is eating' %self.name) def sleep(self): print('%s is sleeping' %self.name) #注意:绑定到对象的方法的这种自动传值的特征,决定了在类中定义的函数都要默认写一个参数self,self可以是任意名字,但是约定俗成地写出self。 s1=OldboyStudent('李坦克','男',18) s2=OldboyStudent('王大炮','女',38) s3=OldboyStudent('牛榴弹','男',78) s1.learn() OldboyStudent.learn(s1) #效果同上
2、绑定方法分类:
绑定方法有两种,一种是绑定给类的方法,一种是绑定给对象的方法。
绑定给类的方法需要使用一个装饰器@classmethod,必须要有一个参数(类本身,默认为cls,可以自己定义,但是约定俗成的写成使用cls)。
class Student: school = "beijing" def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex # 绑定方法分为两种 一种是绑定给对象的,一种绑定给类的 # 绑定给类的方法 使用一个装饰器叫classmethod,必须有一个参数,表示当前类,参数名也可以自己定义,建议不要修改 @classmethod def print_school(cls): # 输出类里面叫school的属性 print(cls.school) # def print_school2(self): # 输出类里面叫school的属性 # print(self.school) # 这是绑定给对象的方法 def sayHello(self): print(self.name, " 说: 你好") # Student.print_school_name() # Student.print_school()
总结:两种绑定方法的使用场景:
a、当要处理的的数据包含在类中时,就应该绑定给类;
b、当要处理的数据包含在对象中时,就应该绑定给对象。
3、非绑定方法:
非绑定方法即在类中即不绑定给类,也不绑定给对象。
特点:没有自动传参的效果,类和对象都能调用,就是一个隶属于类中的普通函数。
应用场景:当这个功能不许要访问类中的数据,也不需要访问对象的数据时,就可以作为一个非绑定方法,应用场景较少。
import json class Student: school = "oldboy" def __init__(self,name,gender,age,cla): self.name = name self.gender = gender self.age = age self.cla = cla def save(self): with open("%s.json"%self.name,"wt",encoding="utf-8") as f: json.dump(self.__dict__,f) #此处既可以使用非绑定方法也可以使用绑定给类的方法: @staticmethod #非绑定方法 def get_obj(name): with open("%s.json"%name,"rt",encoding="utf-8") as f: dic = json.load(f) stu = Student(dic["name"],dic["gender"],dic["age"],dic["cla"]) return stu # stu1 = Student("yuyu","male",18,"5") # stu1.save() stu1 = Student.get_obj("yuyu") print(stu1.gender)