python进阶-面向对象编程:类和对象一:抽象类/接口/继承组合/封装/多态
基本过程:
面向对象的程序设计 如何使用类: 1,实例化 2,引用类的特征(变量)和技能(函数) 如何使用类: 1,实例化 2,引用名(类名.变量名,类名.函数名) 3,实例(实例.类变量,实例.绑定类函数名)
# 面向对象的程序设计: # 找对象---》归纳对象共同的特征与技能,还有每个对象独有的特征---》抽象成类 # 面向对象编程: # 定义类---》实例化对象
看一个学生类简单例子
class Student: country = 'china' def __init__(self,ID,NAME,SEX,PROVINCE,score): self.id = ID self.name = NAME self.sex = SEX self.province = PROVINCE self.score = score def search_score(self): print(self.name,"的分数是",self.score) def study(self): print(self.name,"study") def walk(self): print(self.name,"walk") def attack(self): print("attack") #类的变量 print(Student.country) Student.x=100 print(Student.x) # china # 100 #对象,查询,绑定方法的含义就是,谁调用就是作用谁 s1 =Student('37232323','ddamanter','male','广东省',98) print(s1)#查看对象 <__main__.Student object at 0x1068e82b0> print("Student.__dict__:",Student.__dict__) #查看类的名称空间,以字典的形式包含类的所有属性:变量和方法以及内置函数 # Student.__dict__: {'study': <function Student.study at 0x1058e2b70>, # 'x': 100, '__weakref__': <attribute '__weakref__' of 'Student' objects>, # 'search_score': <function Student.search_score at 0x1058e2a60>, # '__dict__': <attribute '__dict__' of 'Student' objects>, # 'walk': <function Student.walk at 0x1058e2bf8>, # '__init__': <function Student.__init__ at 0x1058e2ae8>, # '__doc__': None, 'attack': <function Student.attack at 0x1058e2c80>, # 'country': 'china', '__module__': '__main__'} print("s1.__dict__:",s1.__dict__) #查看对象的名称空间,以字典的形式包含对象的所有属性 # s1.__dict__: {'score': 98, 'sex': 'male', 'id': '37232323', 'province': '广东省', 'name': 'ddamanter'} print(s1.country) print(s1.id) print(s1.name) print(s1.sex) print(s1.province) print(s1.search_score()) print(s1.study()) print(s1.walk()) # china # 37232323 # ddamanter # male # 广东省 # ddamanter 的分数是 98 # None # ddamanter study # None # ddamanter walk #增加 s1.height="178cm" s1.weight="70kg" s1.age="23" print(s1.height) print(s1.weight) print(s1.age) # 178cm # 70kg # 23 #删除 # del s1.weight # print(s1.weight) #修改 s1.height="180cm" print(s1.height)
一个系统例子
class School: tag="school" def __init__(self,addr): self.addr=addr self.teacher_list=[] self.course_list=[] def admissions(self): print("招生") class Teacher: nationality = "china" school="peking university" def __init__(self,t_name,t_class,t_lesson): self.name=t_name self._class=t_class self.lesson=t_lesson def teach(self): print("teach",self) class Student: nationality = "china" school = "peking university" def __init__(self,id,name,sex): self.id=id self.name=name self.sex=sex self.course_list=[] def search_score(self): print("view grades:",self) def handin(self): pass class Course: def __init__(self,name,price,period): self.name=name self.price=price self.period=period python_obj=Course('python',20000,'1years') linux_obj=Course('python',20000,'1years') s1=Student("001","ada","男") s1.course_list.append(python_obj) print("课程名:%s \n课程价格:%s \n课程时间:%s"%(s1.course_list[0].name,s1.course_list[0].price,s1.course_list[0].period))
什么是抽象类以及特点
import abc # 什么是抽象类:接口只能提供功能的集合,抽象类:本质还是类, # 与普通类额外特点是:加了装饰器@abc.abstractmethod的函数,所有子类必须实现装饰器的方法 class Animal(metaclass=abc.ABCMeta): tag="hello" @abc.abstractmethod def eat(self): pass @abc.abstractmethod def run(self): pass class People(Animal): def eat(self): print("peple eat") def run(self): print("peple run")
基于抽象类的接口与归一化设计
# java 有接口,功能的集合,利用interface ,implament实现, # python 没有,是模仿,但是一般自己的定义都能用 # 接口提取了一堆函数。是函数的集合 # 接口的意义就是必须实现接口内的所有方法 class Animal: def eat(self): raise AttributeError("子类必须使用该方法") def run(self): pass class People(Animal): def eat(self): print("peple eat") def run(self): print("peple run")
面向对象编程的三大特点:封装,继承,多态
类的继承和派生以及组合:
为什么要用继承:解决代码重用问题
# 关联类的继承,是一种什么是什么的关系,比如人是动物,用继承
# 非关联类,是一种什么有什么有什么的关系,比如学生有课程,老师有课程,用类之间的组合
# 英雄的昵称,攻击力,生命值 class Hero: def __init__(self,nickname,agressivity,life_value): self.nickname=nickname self.agressivity=agressivity self.life_value=life_value def attack(self): print("Hero attck") # 具体英雄的昵称,攻击力,生命值,台词 class Garen(Hero): def __init__(self,nickname,agressivity,life_value,script): # Hero.__init__(self,nickname,agressivity,life_value) super(Garen,self).__init__(nickname,agressivity,life_value) #以上两种初始化父类的方法都可以,推荐后一种 self.script=script def attack(self,enemy): Hero.attack(enemy) print("%s attck %s"%(self.nickname,enemy)) class Alex(Hero): def __init__(self,nickname,agressivity,life_value,script): Hero.__init__(self,nickname,agressivity,life_value) self.script=script def attack(self,enemy): Hero.attack(enemy) print("%s attck %s" % (self.nickname,enemy)) g1=Garen("Garen",20,200,"我是盖伦") a1=Alex("Alex",10,300,"我是亚历山大") print(Hero.__bases__) print(Garen.__bases__) # (<class 'object'>,) # (<class '__main__.Hero'>,) print(g1.attack(a1.nickname)) print(g1.script) # Hero attck # Garen attck Alex # None
# 解决非关联类,是(有) 的关系,使用代码重用,用继承不能实现,要用组合,将一个类作为另一个类的输入 # 老师、学生与课程 class Teacher: def __init__(self,name,sex,course): self.name=name self.sex=sex self.course=course class Student: def __init__(self,name,sex,course): self.name=name self.sex=sex self.course=course class Course: def __init__(self,course_name,course_price,course_period): self.course_name=course_name self.course_price=course_price self.course_period=course_period python_obj=Course("python",20000,"7m") t1=Teacher("alex","male",python_obj) s1=Student("adamander","male",python_obj) print(t1.__dict__) print(s1.__dict__) # {'name': 'alex', 'sex': 'male', 'course': <__main__.Course object at 0x1036014e0>} # {'name': 'adamander', 'sex': 'male', 'course': <__main__.Course object at 0x1036014e0>}
# 非关联类老师、学生与生日 class Teacher: def __init__(self,name,sex,birth): self.name=name self.sex=sex self.birth=birth class Student: def __init__(self,name,sex,birth): self.name=name self.sex=sex self.birth=birth class Birth: def __init__(self,birth_date,birth_gift,birth_cake): self.birth_date=birth_date self.birth_gift=birth_gift self.birth_cake=birth_cake birth_obj=Birth("11月11号","bmw car","banana cake") t2=Teacher("alex","male",birth_obj) s2=Student("adamander","male",birth_obj) print(t2.__dict__) print(s2.__dict__) # {'name': 'alex', 'birth': <__main__.Birth object at 0x103601588>, 'sex': 'male'} # {'name': 'adamander', 'birth': <__main__.Birth object at 0x103601588>, 'sex': 'male'}
类的封装
# 第一个层面的封装(什么都不用做): # 创建类和对象会分别创建二者的名称空间,我们只能用类名.或者obj.的方式去访问里面的名字,这本身就是一种封装 # 注意:对于这一层面的封装(隐藏),类名.和实例名.就是访问隐藏属性的接口 # 第二个层面的封装:类中把某些属性和方法隐藏起来(或者说定义成私有的), # 只在类的内部使用、外部无法访问,或者留下少量接口(函数)供外部访问。 # 在python中用双下划线的方式实现隐藏属性(设置成私有的),单下划线是保护变量 # 对于这一层面的封装(隐藏),我们需要在类中定义一个函数(接口函数)在它内部访问被隐藏的属性,然后外部使用接口函数 # 在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的 # 为什么要用property # 将一个类的函数定义成特性以后,对象再去使用的时候obj.name,本来是obj.name(), # 用了@property这个装饰器以后,只需要obj.name # 用户根本无法察觉自己的name是执行了一个函数然后计算出来的, # 这种特性的使用方式遵循了统一访问的原则,大概是类似统一访问属性这种
类的多态
# 多态和多态性: # 多态:一种事物有多种形态,比如一个抽象类有多个子类,动物的多态:人,牛,羊,狗 # 多态性:具有不同功能的函数可以使用相同的函数名 # 同一种行为叫:人的叫,狗的叫,猫的叫 import abc class Animal(metaclass=abc.ABCMeta): @abc.abstractmethod def talk(self): pass class Peoole(Animal): def talk(self): print("people talk") class Sheep(Animal): def talk(self): print("sheep talk") class Cow(Animal): def talk(self): print("cow talk") c=Cow() s=Sheep() p=Peoole() # 多态性:具有不同功能的函数可以使用相同的函数名 def func(animal): animal.talk() func(c) func(s) func(p) # 多态的好处: # 1.增加了程序的灵活性 # 以不变应万变,不论对象千变万化,使用者都是同一种形式去调用,如func(animal) # 2.增加了程序额可扩展性 # 通过继承animal类创建了一个新的类,使用者无需更改自己的代码,还是用func(animal)去调用
接口函数隐藏访问内部隐藏属性
# 接口函数访问内部隐藏数据属性 # class A: # def __init__(self): # self.__x=1 # def tell(self): # print(self.__x) # a=A() # a.tell() # 接口函数访问内部隐藏函数属性 class A: def __fa(self): print("hello word class A") def test(self): print(self.__fa()) class B(A): def hello(self): print("B") b=B() b.test()
经典类和新式类
经典类是py2 的深度优先的类
新式类是py3 的广度优先的类