1. 面向对象学习
1.1 基本概念
两种编程范式:
- 面向过程编程:程序从上到下一步步执行,一步步从上到下,从头到尾的解决问题 ,关键是如何一步一步实现目标。问题:改起来很费劲,后面的子过程依赖前面的过程。
- 面向对象编程:利用“类”和“对象”来创建各种模型来实现对真实世界的描述,从大到小解决问题。
面向对象:Object-Oriented Programming
面向对象的核心:
- Class类:在类中定义了该类对象都具备的属性(variables(data))、共同的方法,不用重复造。
- Object对象:一个对象即是一个类实例化后的实例,叫对象或者实例。
面向对象三大特性:
- 封装(Encapsulation):类,类似封装成了一个胶囊,里面包含着类的数据和方法。对外开放接口即可。
- 继承(Inheritance):一个类可以派生出子类,在这个父类里定义的属性、方法自动被子类继承
- 多态(Polymorphism):“一个接口,多种实现”。一个基类中派生出了不同的子类,且每个子类在继承了同样的方法名的同时又对父类的方法做了不同的实现,这就是同一种事物表现出的多种形态。
写代码时牢记两点:
- 不要写重复代码
- 代码需要经常变更
要达到这个目的:多处复制→函数→面向对象
1.2 一个简单CS面向对象例子
#面向对象基本操作 #定义类 class Role: n = 123 #类变量(此处仅仅举例) def __init__(self, name, role, weapon, life_value=100, money=15000): ''' #构造函数 #在实例化时做一些类的初始化工作 :param self:实例化时它自己 :param name: …… ''' self.name = name #实例变量(静态属性)——赋给了实例(作用域:实例本身) self.role = role self.weapon = weapon self.life_value = life_value self.money = money #析构函数 def __del__(self):#实例释放、销毁(程序退出)的时候自动执行 print("%s 彻底死了。。。。" %self.name) #类的方法,功能(动态属性) def shot(self): print("shooting...") def got_shot(self): print("ah...,I got shot...") def buy_gun(self, gun_name): print("%s just bought %s" % (self.name, gun_name) ) #实例化(对类初始化)(相当于造了一个对象) r1 = Role('Alex', 'police', 'AK47') #生成一个角色 r2 = Role('Jack', 'terrorist', 'B22') #生成一个角色 r1.got_shot() r2.buy_gun("AK47") #其实r1传进去,执行Role.buy_gun()
注:
- 动态属性就是方法,静态属性就是变量。
1.3 实例化的过程
函数:调用函数 ---> 执行 ---> 返回结果
类:
- 原以为:r1 = Role.__init__() ---> return x332422 ,其实不是这样的
- 实际上:r1 = Role(r1, "Alex", "Police", "15000"),把r1传进去 r1.name = "Alex" r1.role = "Poice",不需要返回值。。。因此,构造函数里面有个默认的self
再次理解:
- 在类里面定义参数时,都有一个默认self参数,意义在于每次调用这些功能时,类都知道是哪个实例在调用。
- 调用类中函数时,表面上没有传参,其实传了,把实例它自己传给了self。
- 在实例化时,开辟一块内存,但类里面的内容并没有copy到实例化后的对象中,也就是,这块内存里面并没有类里面的内容。
#实例化的过程 r1 = Role('Alex', 'police', 'AK47') #相当于: Role(r1, 'Alex', 'police', 'AK47') #参数:实例它本身 #实例化干了什么: self.name = name #就是r1.name = name self.role = role
实例化时,可以增、删、改特性,但这部分是存在于这个实例自身的内存中,不影响类。除非更改类,即:Role.n = "ABC"
#属性更改 r1.n = "abc" #实例化时更改属性,不影响类 Role.n = "ABC" #除非像这样直接更改类
1.4 实例变量、类变量
特点:
- 实例变量:描述每一个具体对象的特定属性
- 类变量:大家共用的属性。好处是省内存,如果用实例变量,每实例一次,就得创建一次。
注:
- 实例变量、类变量:先找实例变量,找不到再找类变量
1.5 析构函数
在实例释放、销毁的时候自动执行,通常用于做一些收尾工作,如关闭一些数据库连接、打开的临时文件
注:
- 对于python,只有把变量名(门牌号)删了,内容才被回收。只要门牌号存在,内容就存在,除非程序运行结束。(del r1后,析构函数自动执行)
1.6 私有方法、私有属性
私有:只能自己访问,别人访问不了
定义:前面加俩下划线“__”
体现:封装性
#私有属性: #原来 self.life_value = life_value #改为 self.__life_value = life_value #要想在外部查看血量,只能在内部定义一个功能 def show_status(self): print("name:%s weapon:%s life_val:%s" %(self.name, self.weapon, self.__life_value) #查看血量 print(r1.show_status())
二、 继承性
主要的作用:减少代码,减少重复,相同的内容不用重新定义
#继承性
#父类 class People: def __init__(self, name, age): self.name = name self.age = age def eat(self): print("%s is eating..." %self.name) def talk(self): print("%s is talking..." % self.name) def sleep(self): print("%s is sleeping..." %self.name) #子类1 class Man(People): def piao(self): print("%s is piaoing..." %self.name) #重构父类方法 def sleep(self): People.sleep(self) #保持父类特性 print("man is sleeping") #子类2 class Woman(People): def get_birth(self): print("%s has born a baby..." %self.name) m1 = Man("Alex", 28) m1.eat() m1.piao() m1.sleep() w1 = Woman("Xiao Fang", 26) w1.piao()
#子方法里重构父类-加新参数 #方法1: class Man(People): #加新功能,又不影响原来的父类调用 def __init__(self, name, age, money): People.__init__(self, name, age) #方法1:经典类 self.money = money print("%s 一出生就有 %s money" %(self.name, self.money)) #加新功能方法2:用super class Man(People): #加新功能,又不影响原来的父类调用 def __init__(self, name, age, money): super(Man, self).__init__(name, age) #方法2:新式类 self.money = money print("%s 一出生就有 %s money" %(self.name, self.money)) #方法2不用写父类名字,比较方便,以后多用super
#python3.0的新式类 #经典类 class People: pass #新式类 class People(object): pass
多继承:
#多继承类 class Relation(object): def make_friends(self, obj): #还是把self传进去 print("%s is making friends with %s" %(self.name, obj.name)) self.friends.append(obj)
继承顺序:
- 对于python3.0 ------> 统一按广度优先来继承
- 对于python2.0 ------> 新式类:广度优先 经典类:深度优先
#多继承的继承顺序 class A: def __init__(self): print("A") pass class B(A): # def __init__(self): # print("B") pass class C(A): # def __init__(self): # print("C") pass class D(B, C): #B里面如果有构造函数,D就不会走C的__init__了 pass r1 = D()
多继承例子:
School、SchoolMembeer(Teacher、Student)
#多继承应用实例框架 class School(object): def __init__(self, name, adr): self.name = name self.students = [] def enroll(self, stu_obj): '''学生注册''' self.students.append(stu_obj) class SchoolMember(object): def __init__(self, name, ...): class Teacher(SchoolMember): def __init__(self, name, ..., Salary): super(Teacher, self).__init__(name, age, ...)#重构时相同参数 self.Salary = Salary #实例化 school = School("TJU", "Nankai") t1 = Teacher("Oldboy", 56, "W", 20000, "Linux") s1 = Student("Xiao Ming", 22, "M", 1001, "Python") #应用 school.staffs[0].teach() for stu in school.students: stu.pay_tuition(5000)
#全部代码 class School(object): def __init__(self, name, addr): self.name = name self.addr = addr self.students = [] self. staffs = [] def enroll(self, stu_obj): '''学生注册''' print("为学员 %s 办理注册手续" %stu_obj.name) self.students.append(stu_obj) def hire(self, staff_obj): '''老师注册''' print("雇佣新员工: %s" %staff_obj.name) self.staffs.append(staff_obj) class SchoolMemnber(object): def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex def tell(self): '''学生老师共同需要的方法''' pass class Teacher(SchoolMemnber): def __init__(self, name, age, sex, salary, course): super(Teacher, self).__init__(name, age, sex)#重构时相同参数 self.salary = salary self. course = course def tell(self): '''打印老师信息''' print(''' -----info of Teacher:%s------- Name:%s Age:%s Sex:%s Salary:%s Course:%s '''%(self.name, self.name, self.age, self.sex, self.salary, self.course)) def teach(self): print("%s is teaching course [%s]" %(self.name, self.course)) class Student(SchoolMemnber): def __init__(self, name, age, sex, stu_id, grade): super(Student, self).__init__(name, age, sex) self.stu_id = stu_id self. grade = grade def tell(self): '''打印学生信息''' print(''' -----info of Teacher:%s------- Name:%s Age:%s Sex:%s stu_id:%s grade:%s '''%(self.name, self.name, self.age, self.sex, self.stu_id, self.grade)) def pay_tuition(self, amount): print("%s has paid tuition for $%s" %(self.name, amount)) #实例化 school = School("TJU", "Nankai") t1 = Teacher("Oldboy", 56, "W", 20000, "Linux") t2 = Teacher("Alex", 22, "M", 3000, "Linux") s1 = Student("Xiao Ming", 22, "M", 1001, "Python") s2 = Student("Da Ming", 28, "M", 1003, "Linux") t1.tell() #打印老师信息 school.hire(t1) school.enroll(s1) school.enroll(s2) print(school.students) print(school.staffs) school.staffs[0].teach() for stu in school.students: stu.pay_tuition(5000)
备注:
继承的构造函数如何写:super,写子类的名字就可以。为什么要写:因为继承父类以后,父类也有init构造方法,如果子类不写,就执行父类的了。因为实例化以后参数扩展了,需要重构父类的函数。没有写super,就把父类的替换了,只执行子类的,就没有继承的意义了。相当于先覆盖(__init__),再继承(super),再添加自己的东西
用super的好处,找到哪个类,就继承哪个。(广度查询)
基类最好别传参数,继承作用,不应该单独实例化,既然不实例化,最好别参数
继承2个父类时候,2个父类的参数得一样
还可以用组合:直接调实例化后的类,把里面的功能调过来。这不是继承了,是一种组合,实现代码扩展,
三、 多态性
一种接口,多种实现
作用:实现接口重用
#专门定义一个talk借口,谁进谁叫。(统一的接口) #下周用静态接口,放入父类里面 def animal_talk(obj): # 一个接口,多种形态 obj.talk() c1 = Cat('小晴') d1 = Dog('李磊') animal_talk(c1) animal_talk(d1)