python3.x 基础六:面向对象
面向对象特性
- class 类
一个类是对一类拥有相同属性的对象的描述,在类中定义了这些对象都具备的属性/共同方法
- object对象
一个对象指一个类实例化后的实例,一个类必须经过实例化后才能在程序中调用,一个类可以实例化多个对象,每个对象也可以有不同的属性
- Encapsulation封装
在类中对数据的赋值/内部调用对外部用户是透明的,这使得类成为一个胶囊或者容器,里面包含着类的数据和方法
- Inheritance继承
一个类可以派生出子类,在这个父类里面定义的属性/方法自动被子类继承
- Polymorphism多态
多态是面向对象的重要特性,表现为:一个接口,多种实现,指一个基类(父类)中派生出了不同的子类,且每个子类在继承了同样的方法名的同时有队父类的方法做了不同的实现
变成其实就是一个将具体世界进行抽象化的过程,多态就是抽象化的一种体现,把一系列具体事物的共同点抽象出来,再通过这个抽象的事物,与其他不同的具体事物进行对话
多态允许将子类的对象当做父类的对象使用,某父类型的引用只想其子类型的对象,调用的方法是该子类的方法。这里引用和调用方法的代码在编译前就已经决定了,而引用所指向的对象可以在运行期间动态绑定
类的定义
# /usr/bin/env python # -*- coding: utf-8 -*- # Author:Jenvid.yang class dog(object): nationality = 'CN' # 这是公有属性,在类里直接定义的属性 def __init__(self,name): # 构造函数、构造方法、个初始化方法 self.NAME = name # 这是属性、成员变量 self.__life_value=100 # 这是私有属性,只能在类的内部中访问,外部无法直接调用 def sayhi(self): # 类的方法,self是把实例本身传进来 这是方法、动态属性 print('hello, my name is ', self.NAME) def get_life_value(self): return self.__life_value #将私有属性通过函数返回方法暴露给外界,达到只能查看不能更改效果 d1=dog('wangcai') # 实例化类,类的实例,self也就相当于实例本身 # 1.相当于dog(d1,'wangcai') # 2.d1传给了init的self # 3.self.NAME等同于d1.NAME self.NAME=d1.NAME d1.sayhi() # 4.相当于d1.sayhi(d1),d1传给了sayhi的self # 5.之前d1.NAME已经赋值,此时相当于将赋值后的d1传给了sayhi的self,self里保存了NAME变量 # 6.最后的self.NAME相当于d1.NAME d1.nationality='US' #通过实例更改自己的属性,但是默认值预先存在于内存中,仅仅进行引用,重新赋值后在本地占用新一块内存存储 dog.nationality='US' #通过类名更改全局属性
d1._dog__life_value #强制访问私有属性 实例名._类名__私有属性名
def sayhi(self)
print('goodbye',self.name)
d1.sayhi=sayhi
d1.sayhi(d1) # 重写公有方法
理解:self 实例 私有属性 公有属性 引用 重写公有方法
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class Role(object): def __init__(self,name,role,weapon,life_value=100,money=15000): self.name = name self.role = role self.weapon = weapon self.life_value = life_value self.money = money def shot(self): print('%s is shooting...'% self.name) def got_shot(self): print('i got shot...SOS') def buy_gun(self,gun_name): print("%s had buy gun %s" %(self.name,gun_name)) r1=Role('alex','policeman','b46') r2=Role('oldboy','terrise','B22') r1.shot() r2.got_shot() r2.buy_gun('b51') def buy_gun1(self): print("%s had buy gun xxx" %(self.name)) r2.buy_gun=buy_gun1 r2.buy_gun(r2) alex is shooting... i got shot...SOS oldboy had buy gun b51 oldboy had buy gun xxx
析构方法
def __del__(self): print('del is running ..') #只要数据(引用关系)被清空,就会执行
继承
- 实现继承,使用基类的属性和方法而无需额外编码的能力
- 接口继承,仅使用属性和方法的名称,但是子类必须提供实现的能力,子类重构父类方法
1.继承父类
class Persion(object): def talk(self): print("persion is talking") class BlackPersion(Persion): def walk(self): print('black persion is walking..') b=BlackPersion() b.walk() b.talk() output: black persion is walking.. persion is talkin
2.重写父类方法
class Persion(object): def talk(self): print("persion is talking") class BlackPersion(Persion): def talk(self): print("speak balalala") def walk(self): print('black persion is walking..') b=BlackPersion() b.walk() b.talk() output: black persion is walking.. speak balalal
3.父类带有构造函数
class Persion(object): def __init__(self,name,age): self.name=name self.age=age def talk(self): print("persion is talking") class WhitePersion(Persion): pass class BlackPersion(Persion): def talk(self): print("speak balalala") def walk(self): print('black persion is walking..') b=BlackPersion('blackone',30) # 1. 如果子类没有自己的构造函数,将调用父类构造函数,否则报错,因此实例化时要传入实参 b.walk() b.talk() output: black persion is walking.. speak balalala
4.子类有自己的构造函数并且有新的属性
# /usr/bin/env python # -*- coding: utf-8 -*- # Author:Jenvid.yang class Persion(object): def __init__(self,name,age): self.name=name self.age=age self.plant='earth' def talk(self): print("persion is talking") class WhitePersion(Persion): pass class BlackPersion(Persion): def __init__(self,name,age,strength): # 2.先继承,后重构,增加子类自己的属性 Persion.__init__(self,name,age) # 3.调用父类构造函数,将子类的self,name,age传给父类,获取父类原有的属性 print(self.name,self.age,self.plant) self.strength=strength def talk(self): Persion.talk(self) # 4.调用父类方法,没用,不这么干,一般只是调用父类构造函数 print("speak balalala") def walk(self): print('black persion is walking..') b=BlackPersion('blackone',30,'strong') # 1. 如果子类传参,并且没有自己的构造函数,将调用父类构造函数,否则报错 b.walk() b.talk() output: blackone 30 earth black persion is walking.. speak balalala
5.课堂类继承例子
#/usr/bin/env python #-*- coding: utf-8 -*- #Author:jenvid.yang class SchoolMember(object): '''学校父类''' member = 0 def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex self.enroll() # 每次实例化对象的时候调用一次 def enroll(self): '''注册''' print("%s just enrolled a new shcool member"%self.name) SchoolMember.member+=1 # 全局加1 def tell(self): for k,v in self.__dict__.items(): # 用__dict__方法遍历不同实例的属性 print(k,v) def __del__(self): print('删除%s'%self.name) # 垃圾回收,程序结束的时候也会自动执行 SchoolMember.member-=1 class Teacher(SchoolMember): '''讲师类''' def __init__(self,name,age,sex,salary,course): # 扩展自己的属性 SchoolMember.__init__(self,name,age,sex) #继承父类属性 # 经典类写法
#super(Teacher,self).__init__(name,age,sex) # 新式类写法
self.salary=salary self.course=course def teaching(self): print("teacher %s is teaching course %s" %(self.name,self.course)) class Studen(SchoolMember): '''学生类''' def __init__(self,name,age,sex,course,tution): SchoolMember.__init__(self,name,age,sex) self.course=course self.tution=tution self.amount=0 def pay_tutition(self,amount): print("student %s has just paied %s" %(self.name,self.amount)) self.amount+=amount t1 = Teacher('alex',18,'M',3000,'py') print(SchoolMember.member) # print(t1.__dict__) s1 = Studen('stu1',18,'F','py',3000) print(SchoolMember.member) s2 = Studen('stu2',18,'M','lnx',4000) print(SchoolMember.member) t1.tell() s1.tell() del s1 print(SchoolMember.member)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
alex just enrolled a new shcool member 1 {'name': 'alex', 'course': 'py', 'salary': 3000, 'sex': 'M', 'age': 18} stu1 just enrolled a new shcool member 2 stu2 just enrolled a new shcool member 3 name alex course py salary 3000 sex M age 18 amount 0 name stu1 course py tution 3000 sex F age 18 删除stu1 2 删除stu2 删除alex
经典类与新式类
新式类:
- 定义语法:
class 类名(object):
- 继承父类构造函数语法
super(父类名.self).__init__(变量1,2..)
经典类
- 定义语法:
class 类名:
- 继承父类构造函数语法
类名.__init__(self,变量1,2..)
多继承
3.0是广度继承路径
2.0新式继承是广度路径,经典继承是纵向路径
什么时候使用面向对象编程
- 如果存在多个函数需要传入多个共同的参数时
- 根据一个模板创建多个东西
- 重复方法封装起来
self--就是当前调用方法的对象
静态字段使用场景,每个对象中保存相同的东西时,可以使用静态字段
封装--
类中封装了字段/方法
对象中封装了普通字段的值
对象中封装对象,再封装对象
class F1: def __init__(self,n): self.N=n print('F1') class F2: def __init__(self,arg1): self.a=arg1 print('F2') class F3: def __init__(self,arg2): self.b=arg2 print('F3') o1=F1('alex') # 4.o3.b.a=F1('alex') 5.self==o3.b.a 6. alex==o3.b.a.N o2=F2(o1) # 2.arg1==o1 o2.a==o1 3. o3.b.a==o1 o3=F3(o2) # 1.arg2==o2 o3.b==o2 #通过o3如何输出alex #o3=F3(F2(o1) == F3(F2(F1('alex'))) print(o3.b.a.N)
继承注意:
class F1: def __init__(self): print('F1') def a1(self): print('F1a1') def a2(self): print('F1a2') class F2(F1): def __init__(self): print('F2') def a1(self): self.a2() print('F2a1') def a2(self): print('F2a2') class F3(F2): def __init__(self): print('F3') def a2(self): print('F3a2') # def a1(self): # print('F3a1') obj=F3() obj.a1() # 1.实例化F3,调用F3中的a1方法 # 2.F3中没有a1方法,到父类F2中找到a1方法 # 3.self.a2()方法回到类F3中调用自己的a2,打印F3a2,self代表的是obj,因此回到F3找 # 4.打印F2中的F2a1
直接调用类中的方法:
字段:
普通字段-保存在对象中
静态字段-保存在类中
方法:
普通方法-保存在类中,调用者是对象
class F1: def __init__(self,name): self.name=name def a1(self): print(self.name) obj=F1('alex') obj.a1() class F1: def a1(self): print('alex') obj=F1() obj.a1() # 没有封装任何东西,会浪费内存空间,使用静态方法 #静态方法,可以有任意个参数 #完成函数一样的功能 #调用这是类(无需创建对象) class F1: @staticmethod def a1(): print('alex') F1.a1()