5.1、初识面向对像
编程范式的介绍
1.三大编程范式(编程的三种方法/风格)
面向过程编程
定义:面向过程的程序设计的核心是过程(流水线式思维),过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西。即把一个大的问题细分成小的问题,执行时候从第一步执行到最后一步。
优点:极大的降低了写程序的复杂度,只需要顺着要执行的步骤,堆叠代码即可。
缺点:一套流水线或者流程就是用来解决一个问题,代码牵一发而动全身。
def interactive(): name=input('>>: ').strip() pwd=input('>>: ').strip() email=input('>> ').strip() return { 'name':name, 'pwd':pwd, 'email':email } def check(user_info): is_valid=True if len(user_info['name']) == 0: print('用户名不能为空') is_valid=False if len(user_info['pwd']) < 6: print('密码不能少于6位') is_valid=False if not re.search(r'@.*?\.com$',user_info['email']): print('邮箱格式不合法') is_valid=False return { 'is_valid':is_valid, 'user_info':user_info } def register(check_info): if check_info['is_valid']: with open('db.json','w',encoding='utf-8') as f: json.dump(check_info['user_info'],f) def main(): user_info=interactive() check_info=check(user_info) register(check_info) if __name__ == '__main__': main()
函数式编程
定义:数学层面的函数和编程层面函数两者和二为一的编程
面向对象编程(OOP)
定义:面向对象”是一种编程范式,对函数进行分类和封装,让开发“更快更好更强...
优点:解决了程序的扩展性。对某一个对象单独修改,会立刻反映到整个体系中,如对游戏中一个人物参数的特征和技能修改都很容易。
缺点:可控性差,无法向面向过程的程序设计流水线式的可以很精准的预测问题的处理流程与结果,面向对象的程序一旦开始就由对象之间的交互解决问题,即便是上帝也无法预测最终结果。于是我们经常看到一个游戏人某一参数的修改极有可能导致阴霸的技能出现,一刀砍死3个人,这个游戏就失去平衡。
应用场景:需求经常变化的软件,一般需求的变化都集中在用户层,互联网应用,企业内部软件,游戏等都是面向对象的程序设计大显身手的好地方。
在python 中面向对象的程序设计并不是全部。
面向对象编程可以使程序的维护和扩展变得更简单,并且可以大大提高程序开发效率 ,另外,基于面向对象的程序可以使它人更加容易理解你的代码逻辑,从而使团队开发变得更从容。
编程步骤:
1)把构成问题的事务分解、抽象成各个对象;
2)结合这些对象的共有属性,抽象出类;
3)类层次化结构设计--继承 和 合成;
4)用类和实例进行设计和实现来解决问题。
(说明:三中编程方法没有高低之分,各有优劣)
#先定义类 class LuffyStudent: def __init__(self,name): self.name=name school='luffycity' def learn(self): print('%s is learning'%(self.name)) def eat(self): print('is sleeping') #后产生对象 stu1=LuffyStudent('eggo') LuffyStudent.learn(stu1,) # stu2=LuffyStudent() # stu3=LuffyStudent() # print(stu1) # print(stu2) # print(stu3)
面向对象的介绍
面向对象编程是一种编程方式,此编程方式的落地需要使用 “类” 和 “对象” 来实现,所以,面向对象编程其实就是对 “类” 和 “对象” 的使用
面向对象的名词解释
类:一个类即是对一类拥有相同属性的对象的抽象、蓝图、原型、模板。在类中定义了这些对象的都具备的属性(variables(data))、共同的方法
属性:人类包含很多特征,把这些特征用程序来描述的话,叫做属性,比如年龄、身高、性别、姓名等都叫做属性,一个类中,可以有多个属性
方法:人类不止有身高、年龄、性别这些属性,还能做好多事情,比如说话、走路、吃饭等,相比较于属性是名词,说话、走路是动词,这些动词用程序来描述就叫做方法。
实例(对象):一个对象即是一个类的实例化后实例,一个类必须经过实例化后方可在程序中调用,一个类可以实例化多个对象,每个对象亦可以有不同的属性,就像人类是指所有人,每个人是指具体的对象,人与人之前有共性,亦有不同
实例化:把一个类转变为一个对象的过程就叫实例化
类的介绍:
定义:把一类事物的相同的特征和动作整合到一起就是类(如 人、狗、老虎))是一个抽象的概念,在python中类是一个模板,模板里可以包含多个函数,函数里实现一些功能
类的创建:
class Foo: #clss 为关键字,表示要创建类,Foo是类的名称
def __init__(self,参数1,参数2): #self为特殊参数,必填
self.对象的属性1 = 参数1
self.对象的属性2 = 参数2
def 方法名(self):pass
def 方法名2(self):pass
对象名 = Foo (1,2) #对象就是实例,代表一个具体的东西
#类名() : 类名+括号就是实例化一个类,相当于调用了__init__方法
#括号里传参数,参数不需要传self,其他与init中的形参一一对应
#结果返回一个对象
对象名.对象的属性 #查看对象的属性,直接用 对象名.属性名 即可
对象名.方法名() #调用类中的方法,直接用 对象名.方法名() 即可
'''
class 类名:
'类的文档字符串'
类体
'''
# 创建一个类
'''
class Person: #定义一个人类
role = 'person' #人的角色属性都是人
def walk(self): #人都可以走路,也就是有一个走路方法,也叫动态属性
print("person is walking...")
'''
#先定义类
class LuffyStudent: # 定义一个 学生类
'''test'''
school='luffycity' #数据属性
def learn(self): #函数属性
print('is learning')
def eat(self): #函数属性
print('is sleeping')
print(LuffyStudent.__dict__)
类的作用
类有两种作用属性引用和实例化
属性引用(类名.属性)
类有两种属性:数据属性和函数属性
1. 类的数据属性是所有对象共享的
2. 类的函数属性是绑定给对象用的
class Person: #定义一个人类 role = 'person' #类属性----静态属性 人的角色属性都是人 def walk(self): #这里的函数叫做方法---动态属性.self必须写。 print("person is walking...") print(Person.role) #查看类属性,查看人的role属性 print(Person.walk) #查看类方法,引用人的走路方法,注意,这里不是在调用,用类名去调用方法名,打印出来的是内存地址
实例化(对象名 = 类名(参数))
实例化的过程就是类——>对象的过程,类名加括号就是实例化,会自动触发__init__函数的运行,可以用它来为每个实例定制自己的特征
class Person: #定义一个人类 role = 'person' #人的角色属性都是人 def __init__(self,name): self.name = name # 每一个角色都有自己的昵称; def walk(self): #人都可以走路,也就是有一个走路方法 print("person is walking...") egg = Person('egon') #实例化:类名(参数) 就等于在执行Person.__init__() #执行完__init__()就会返回一个对象。这个对象类似一个字典,存着属于这个人本身的一些属性和方法。 print(egg) #返回的是一个对象 print(egg.name) #查看属性直接 对象名.属性名 print(egg.walk()) #调用方法, 对象名.方法名()
原本我们只有一个Person类,在这个过程中,产生了一个egg对象,有自己具体的名字、攻击力和生命值。
关于self,在实例化时自动将对象/实例本身传给__init__的第一个参数,是固定的,你也可以给他起个别的名字,但是正常人都不会这么做。
类的增删改查
# 查 #print(LuffyStudent.school) # LuffyStudent.__dict__['school'] #print(LuffyStudent.learn) # LuffyStudent.__dict__['learn'] # 增 #LuffyStudent.county='China' #print(LuffyStudent.__dict__) #print(LuffyStudent.county) # 删 #del LuffyStudent.county #print(LuffyStudent.__dict__) # 改 #LuffyStudent.school='Luffycity'
类的特殊属性
我们定义的类的属性到底存到哪里了?有两种方式查看
dir(类名):查出的是一个名字列表
类名.__dict__:查出的是一个字典,key为属性名,value为属性值
类名.__name__# 类的名字(字符串) 类名.__doc__# 类的文档字符串 类名.__base__# 类的第一个父类(在讲继承时会讲) 类名.__bases__# 类所有父类构成的元组(在讲继承时会讲) 类名.__dict__# 类的字典属性 类名.__module__# 类定义所在的模块 类名.__class__# 实例对应的类(仅新式类中) print(Person.__name__, type(Person.__name__)) #查看类的名字(这里的类名是字符串类型的) print(Person.__dict__) #查出的是一个字典,key为属性名,value为属性值 print(Person.__doc__) # 就是把注释显示出来,文档字符串 print(dir(Person)) #查看类的方法,以列表的形式显示出来 print(Person.__module__) #类定义所在的模块 print(Person.__class__) # 实例对应的类(仅新式类中) print(isinstance(egg,Person)) #判断对象 是否是类的实例 print(Person.__bases__) # 类所有父类构成的元组(在讲继承时会讲))
对象/实例的介绍
定义:就是基于类而创建的一个具体的事物(具体存在的)也是特征和动作整合到一起,在python中对象是根据模板创建的实例,通过实例对象可以执行类中的函数。
#对象是关于类而实际存在的一个例子,即实例.实例化的过程就是类——>对象的过程
#__init__方法用来为对象定制对象自己独有的特征
#先定义类
class LuffyStudent: # 定义一个 学生类
school='luffycity' #数据属性
def __init__(self,name,sex,age):
self.Name=name
self.Sex=sex
self.Age=age
def learn(self): #函数属性
print('is learning')
def eat(self): #函数属性
print('is sleeping')
# 后产生对象
stu1=LuffyStudent('王二丫','女',18) # LuffyStudent.__init__(stu1,'王二丫','女',18)
#加上__init__方法后,实例化的步骤
# 1、先产生一个空对象stu1
# 2、LuffyStudent.__init__(stu1,'王二丫','女',18)
对象的属性 属性引用
x='global'
class LuffyStudent:
school='luffycity'
def __init__(self,name,sex,age):
self.Name=name
self.Sex=sex
self.Age=age
def learn(self,x):
print('%s is learning %s' %(self.Name,x))
def eat(self):
print('%s is sleeping' %self.Name)
#后产生对象
stu1=LuffyStudent('王二丫','女',18)
stu2=LuffyStudent('李三炮','男',38)
stu3=LuffyStudent('张铁蛋','男',48)
# print(stu2.__dict__)
# print(stu3.__dict__)
#类中的数据属性:是所以对象共有的
# print(LuffyStudent.school,id(LuffyStudent.school))
# print(stu1.school,id(stu1.school))
# print(stu2.school,id(stu2.school))
# print(stu3.school,id(stu3.school))
#类中的函数属性:是绑定给对象使用的,绑定到不同的对象是不同的绑定方法,对象调用绑定方式时,会把对象本身当作第一个传入,传给self
# 类调用方法
# print(LuffyStudent.learn)
# LuffyStudent.learn(stu1,'python')
# LuffyStudent.learn(stu2,'go')
# LuffyStudent.learn(stu3,'php')
## 对象调用方法
# print(stu1.learn)
# print(stu2.learn)
# print(stu3.learn)
# stu1.learn('python') #learn(stu1,python)
# stu2.learn('go')
# stu3.learn('php')
#
stu1.x='from stu1'
LuffyStudent.x='from Luffycity class'
print(stu1.__dict__)
print(stu1.x)
print(LuffyStudent.__dict__)
'''
1、属性查找
强调:类的属性与对象的属性,访问时必须加前缀
先从对象自己的名称空间中找,如果没有则去类的名称空间中找
2、绑定方法
类中定义的函数是类的函数属性,就是一个普通函数,没有自动传参的效果
但类中定义的函数其实是绑定给对象用的,称之为绑定方法,绑定方法的特殊之处
绑定给谁就应该由谁来调用,谁来调用就会将谁当做第一个位置参数自动传入
对象的增删该查:
#查
'''
print(stu1.__dict__)
#print(stu1.Name)
#print(stu1.Sex)
#print(stu1.Age)
'''
#改
'''
# stu1.Name='李二丫'
# print(stu1.__dict__)
# print(stu1.Name)
'''
#删除
'''
# del stu1.Name
# print(stu1.__dict__)
'''
#增
'''
# stu1.class_name='python开发'
# print(stu1.__dict__)
#
'''
对象之间的交互
class Garen:
camp='Demacia'
def __init__(self,nickname,life_value,aggresivity):
self.nickname=nickname
self.life_value=life_value
self.aggresivity=aggresivity
def attack(self,enemy):
enemy.life_value-=self.aggresivity
#r1.life_value-=g1.aggresivity
class Riven:
camp = 'Noxus'
def __init__(self, nickname, life_value, aggresivity):
self.nickname = nickname
self.life_value = life_value
self.aggresivity = aggresivity
def attack(self, enemy):
enemy.life_value -= self.aggresivity
g1=Garen('草丛伦',100,30)
r1=Riven('可爱的锐雯雯',80,50)
# print(r1.life_value)
# g1.attack(r1)
# print(r1.life_value)
面向对象的组合用法
#****************************面向对象的组合用法************************************************
'''
软件重用的重要方式除了继承之外还有另外一种方式,即:组合
组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合
'''
#列子一
class Weapon:
def prick(self, obj): # 这是该装备的主动技能,扎死对方
obj.life_value -= 500 # 假设攻击力是500
class Person: # 定义一个人类
role = 'person' # 人的角色属性都是人
def __init__(self, name):
self.name = name # 每一个角色都有自己的昵称;
self.weapon = Weapon() # 给角色绑定一个武器;
egg = Person('egon')
egg.weapon.prick()
# egg组合了一个武器的对象,可以直接egg.weapon来使用组合类中的所有方法
#列子二
class People:
school='luffycity'
def __init__(self,name,age,sex):
self.name=name
self.age=age
self.sex=sex
class Teacher(People):
def __init__(self,name,age,sex,level,salary,):
super().__init__(name,age,sex)
self.level=level
self.salary=salary
def teach(self):
print('%s is teaching' %self.name)
class Student(People):
def __init__(self, name, age, sex, class_time,):
super().__init__(name,age,sex)
self.class_time=class_time
def learn(self):
print('%s is learning' % self.name)
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
def tell_info(self):
print('课程名<%s> 课程价钱<%s> 课程周期<%s>' %(self.course_name,self.course_price,self.course_period))
class Date:
def __init__(self,year,mon,day):
self.year=year
self.mon=mon
self.day=day
def tell_info(self):
print('%s-%s-%s' %(self.year,self.mon,self.day))
# teacher1=Teacher('alex',18,'male',10,3000,)
# teacher2=Teacher('egon',28,'male',30,3000,)
# python=Course('python',3000,'3mons')
# linux=Course('linux',2000,'4mons')
# print(python.course_name)
# teacher1.course=python
# teacher2.course=python
# print(python)
# print(teacher1.course)
# print(teacher2.course)
# print(teacher1.course.course_name)
# print(teacher2.course.course_name)
# teacher1.course.tell_info()
# student1=Student('张三',28,'female','08:30:00')
# student1.course1=python
# student1.course2=linux
# student1.course1.tell_info()
# student1.course2.tell_info()
# student1.courses=[]
# student1.courses.append(python)
# student1.courses.append(linux)
student1=Student('张三',28,'female','08:30:00')
d=Date(1988,4,20)
python=Course('python',3000,'3mons')
student1.birh=d
student1.birh.tell_info()
student1.course=python
student1.course.tell_info()
类命名空间与对象、实例的命名空间
创建一个类就会创建一个类的名称空间,用来存储类中定义的所有名字,这些名字称为类的属性
而类有两种属性:静态属性和动态属性
- 静态属性就是直接在类中定义的变量
- 动态属性就是定义在类中的方法
创建一个对象/实例就会创建一个对象/实例的名称空间,存放对象/实例的名字,称为对象/实例的属性
在obj.name会先从obj自己的名称空间里找name,找不到则去类中找,类也找不到就找父类...最后都找不到就抛出异常
面向对象的小结
#对象:特征与技能的结合体
#类:类是一系列对象相似的特征与相似的技能的结合体
1、类
对象是特征与技能的结合体,而类则一系列对象相同特征与技能的结合体
对象是具体存在的,而类是总结出来的抽象的概念
类本质就是一个容器(名称空间)
对象本质也是一个容器(名称空间)
2、 类与对象
在现实世界中:一定是先有一个个具体存在的对象,然后随着人类文明的发展由人站在不同的角度总结出来的种类的概念
在程序中:先定义类,后调用类来产生对象
3 4-jQuery:
class 类名:
def __init__(self,参数1,参数2):
self.对象的属性1 = 参数1
self.对象的属性2 = 参数2
def 方法名(self):pass
def 方法名2(self):pass
对象名 = 类名(1,2) #对象就是实例,代表一个具体的东西
#类名() : 类名+括号就是实例化一个类,相当于调用了__init__方法
#括号里传参数,参数不需要传self,其他与init中的形参一一对应
#结果返回一个对象
对象名.对象的属性1 #查看对象的属性,直接用 对象名.属性名 即可
对象名.方法名() #调用类中的方法,直接用 对象名.方法名() 即可
面向对象的三大特性
继承
定义:继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类
在python中的继承注意两点:
1. 在python中支持一个子类同时继承多个父类,
2. python中类分为两种:
新式类:但凡继承object的类,以及该类的子类。。。都是新式类。 在python3中一个类如果没有继承人类类,默认继承object类,即python3中所有的类都是新式类
经典类: 没有继承object的类,以及该类的子类。。。都是经典类。在python2中才区分新式类与经典类
python中类的继承分为:单继承和多继承
class ParentClass1: #定义父类
pass
class ParentClass2: #定义父类
pass
class SubClass1(ParentClass1): #单继承,基类是ParentClass1,派生类是SubClass
pass
class SubClass2(ParentClass1,ParentClass2): #python支持多继承,用逗号分隔开多个继承的类
pass
查看继承
如果没有指定基类,python的类会默认继承object类,object是所有python类的基类,它提供了一些常见方法(如__str__)的实现。
print(SubClass1.__bases__) #__base__只查看从左到右继承的第一个子类,__bases__则是查看所有继承的父类
#(<class '__main__.ParentClass1'>,)
print(SubClass2.__bases__)
#(<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>)
print( SubClass1.__bases__ )
#__base__只查看从左到右继承的第一个子类
>>>(<class '__main__.ParentClass1'>,)
print(SubClass2.__bases__)
#__bases__是查看所有继承的父类
>>>(<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>)
##如果没有指定基类,python的类会默认继承object类,object是所有python类的基类,它提供了一些常见方法(如__str__)的实现。
print(ParentClass1.__bases__)
>>>(<class 'object'>,)
print(ParentClass2.__bases__)
>>>(<class 'object'>,)
经典类:在python2中,class Dad: 不会继承object,这样的类叫做经典类(它叫经典类,不是因为它经典,而是因为它比较老)
新式类:在python3中,python会默认继承object类(一切皆对象),class Dad 就相当于python2中的 class Dad(object) #新式类
而且python3中没有经典类了
派生:子类在父类方法和属性的基础上产生了新的方法和属性。
1.在父类的基础上产生子类,产生的子类就叫做派生类
2.父类里没有的方法,在子类中有了,这样的方法就叫做派生方法。
3.父类里有,子类也有的方法,就叫做方法的重写(就是把父类里的方法重写了)
说明:
1.子类可以使用父类的所有属性和方法
2.如果子类有自己的方法,就执行自己的;如果子类没有自己的方法,就会找父类的。
3.如果子类里面没有找到,父类里也没有找到,就会报错
4.如果子类中实现了调用父类的方法
在类内:super(子类,self).方法名() supper().__init__(参数)
在类外:super(子类名,对象名).方法名()
class Animal:
'''
人和狗都是动物,所以创造一个Animal基类
'''
def __init__(self, name, aggressivity, life_value):
self.name = name # 人和狗都有自己的昵称;
self.aggressivity = aggressivity # 人和狗都有自己的攻击力;
self.life_value = life_value # 人和狗都有自己的生命值;
def eat(self):
print('%s is eating'%self.name)
class Dog(Animal):
'''
狗类,继承Animal类
'''
def bite(self, people):
'''
派生:狗有咬人的技能
:param people:
'''
people.life_value -= self.aggressivity
class Person(Animal):
'''
人类,继承Animal
'''
def attack(self, dog):
'''
派生:人有攻击的技能
:param dog:
'''
dog.life_value -= self.aggressivity
egg = Person('egon',10,1000)
ha2 = Dog('二愣子',50,1000)
print(ha2.life_value)
print(egg.attack(ha2))
print(ha2.life_value)
# 注意:像ha2.life_value之类的属性引用,会先从实例中找life_value然后去类中找,然后再去父类中找...直到最顶级的父类。
# 在子类中,新建的重名的函数属性,在编辑函数内功能的时候,有可能需要重用父类中重名的那个函数功能,应该是用调用普通函数的方式,即:类名.func(),此时就与调用普通函数无异了,因此即便是self参数也要为其传值
继承的实现
python到底是如何实现继承的,对于你定义的每一个类,python会计算出一个方法解析顺序(MRO)列表,这个MRO列表就是一个简单的所有基类的线性顺序列表 # 例如
# >>> F.mro() #等同于F.__mro__
# [<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
继承顺序
#1、经典类
#在python2中-》经典类:没有继承object的类,以及它的子类都称之为经典类
# class Foo:
# pass
# class Bar(Foo):
# pass
#
# #在python2中-》新式类:继承object的类,以及它的子类都称之为新式类
# class Foo(object):
# pass
#
# class Bar(Foo):
# pass
'''继承顺序按深度优先'''
#2、新式类
#在python3中-》新式类:一个类没有继承object类,默认就继承object
# class Foo():
# pass
# print(Foo.__bases__)
'''继承顺序按广度优先'''
#验证多继承情况下的属性查找
class A(object):
def test(self):
print('from A')
class B(A):
def test(self):
print('from B')
class C(A):
def test(self):
print('from C')
class D(B):
def test(self):
print('from D')
class E(C):
def test(self):
print('from E')
class F(D,E):
# def test(self):
# print('from F')
pass
f1=F()
f1.test()
print(F.__mro__) #只有新式才有这个属性可以查看线性列表,经典类没有这个属性
#新式类继承顺序:F->D->B->E->C->A
#经典类继承顺序:F->D->B->A->E->C
#python3中统一都是新式类
#pyhon2中才分新式类与经典类
子类中调用父类的方法
方法一:父类名.父类方法() 指名道姓(不依赖继承)
#_*_coding:utf-8_*_
__author__ = 'Linhaifeng'
class Vehicle: #定义交通工具类
Country='China'
def __init__(self,name,speed,load,power):
self.name=name
self.speed=speed
self.load=load
self.power=power
def run(self):
print('开动啦...')
class Subway(Vehicle): #地铁
def __init__(self,name,speed,load,power,line):
Vehicle.__init__(self,name,speed,load,power)
self.line=line
def run(self):
print('地铁%s号线欢迎您' %self.line)
Vehicle.run(self)
line13=Subway('中国地铁','180m/s','1000人/箱','电',13)
line13.run()
方法二:super()
class Vehicle: #定义交通工具类
Country='China'
def __init__(self,name,speed,load,power):
self.name=name
self.speed=speed
self.load=load
self.power=power
def run(self):
print('开动啦...')
class Subway(Vehicle): #地铁
def __init__(self,name,speed,load,power,line):
#super(Subway,self) 就相当于实例本身 在python3中super()等同于super(Subway,self)
super().__init__(name,speed,load,power)
self.line=line
def run(self):
print('地铁%s号线欢迎您' %self.line)
super(Subway,self).run()
class Mobike(Vehicle):#摩拜单车
pass
line13=Subway('中国地铁','180m/s','1000人/箱','电',13)
line13.run()
接口类
继承有两种用途:
一:继承基类的方法,并且做出自己的改变或者扩展(代码重用)
二:声明某个子类兼容于某基类,定义一个接口类Interface,接口类中定义了一些接口名(就是函数名)且并未实现接口的功能,子类继承接口类,并且实现接口中的功能
# 接口提取了一群类共同的函数,可以把接口当做一个函数的集合,然后让子类去实现接口中的函数。
# 这么做的意义在于归一化,什么叫归一化,就是只要是基于同一个接口实现的类,那么所有的这些类产生的对象在使用时,从用法上来说都一样。
# 归一化,让使用者无需关心对象的类是什么,只需要的知道这些对象都具备某些功能就可以了,这极大地降低了使用者的使用难度。
# 比如:我们定义一个动物接口,接口里定义了有跑、吃、呼吸等接口函数,这样老鼠的类去实现了该接口,松鼠的类也去实现了该接口,由二者分别产生一只老鼠和一只松鼠送到你面前,
即便是你分别不到底哪只是什么鼠你肯定知道他俩都会跑,都会吃,都能呼吸。
import abc
class Animal(metaclass=abc.ABCMeta): #只能被继承,不能被实例化
all_type='animal'
@abc.abstractmethod
def run(self):
pass
@abc.abstractmethod
def eat(self):
pass
# animal=Animal() 会被报错
class People(Animal):
def run(self):
print('people is running')
def eat(self):
print('people is eating')
class Pig(Animal):
def run(self):
print('people is walking')
def eat(self):
print('people is eating')
class Dog(Animal):
def run(self):
print('people is walking')
def eat(self):
print('people is eating')
# peo1=People()
# pig1=Pig()
# dog1=Dog()
# #
# #
# peo1.eat()
# pig1.eat()
# dog1.eat()
#
# print(peo1.all_type)
抽象类
# 如果说类是从一堆对象中抽取相同的内容而来的,那么抽象类就是从一堆类中抽取相同的内容而来的,内容包括数据属性和函数属性
import abc #利用abc模块实现抽象类
class All_file(metaclass=abc.ABCMeta):
all_type='file'
@abc.abstractmethod #定义抽象方法,无需实现功能
def read(self):
'子类必须定义读功能'
pass
@abc.abstractmethod #定义抽象方法,无需实现功能
def write(self):
'子类必须定义写功能'
pass
# class Txt(All_file):
# pass
#
# t1=Txt() #报错,子类没有定义抽象方法
class Txt(All_file): #子类继承抽象类,但是必须定义read和write方法
def read(self):
print('文本数据的读取方法')
def write(self):
print('文本数据的读取方法')
class Sata(All_file): #子类继承抽象类,但是必须定义read和write方法
def read(self):
print('硬盘数据的读取方法')
def write(self):
print('硬盘数据的读取方法')
class Process(All_file): #子类继承抽象类,但是必须定义read和write方法
def read(self):
print('进程数据的读取方法')
def write(self):
print('进程数据的读取方法')
wenbenwenjian=Txt()
yingpanwenjian=Sata()
jinchengwenjian=Process()
#这样大家都是被归一化了,也就是一切皆文件的思想
wenbenwenjian.read()
yingpanwenjian.write()
jinchengwenjian.read()
print(wenbenwenjian.all_type)
print(yingpanwenjian.all_type)
print(jinchengwenjian.all_type)
多态
多态指的是一类事物有多种形态
动物有多种形态:人,狗,猪
import abc class Animal(metaclass=abc.ABCMeta): #同一类事物:动物 @abc.abstractmethod def talk(self): pass class People(Animal): #动物的形态之一:人 def talk(self): print('say hello') class Dog(Animal): #动物的形态之二:狗 def talk(self): print('say wangwang') class Pig(Animal): #动物的形态之三:猪 def talk(self): print('say aoao')
文件有多种形态:文本文件,可执行文件
import abc
class File(metaclass=abc.ABCMeta): #同一类事物:文件
@abc.abstractmethod
def click(self):
pass
class Text(File): #文件的形态之一:文本文件
def click(self):
print('open file')
class ExeFile(File): #文件的形态之二:可执行文件
def click(self):
print('execute file')
多态性
多态性是指在不考虑实例类型的情况下使用实例,分为静态多态性和动态多态性
在面向对象方法中一般是这样表述多态性:向不同的对象发送同一条消息(!!!obj.func():是调用了obj的方法func,又称为向obj发送了一条消息func),不同的对象在接收时会产生不同的行为(即方法)。也就是说,每个对象可以用自己的方式去响应共同的消息。所谓消息,就是调用函数,不同的行为就是指不同的实现,即执行不同的函数。
比如:老师.下课铃响了(),学生.下课铃响了(),老师执行的是下班操作,学生执行的是放学操作,虽然二者消息一样,但是执行的效果不同
多态性的好处
1.增加了程序的灵活性
以不变应万变,不论对象千变万化,使用者都是同一种形式去调用,如func(animal)
2.增加了程序额可扩展性
通过继承animal类创建了一个新的类,使用者无需更改自己的代码,还是用func(animal)去调用
>>> class Cat(Animal): #属于动物的另外一种形态:猫 ... def talk(self): ... print('say miao') ... >>> def func(animal): #对于使用者来说,自己的代码根本无需改动 ... animal.talk() ... >>> cat1=Cat() #实例出一只猫 >>> func(cat1) #甚至连调用方式也无需改变,就能调用猫的talk功能 say miao ''' 这样我们新增了一个形态Cat,由Cat类产生的实例cat1,使用者可以在完全不需要修改自己代码的情况下。使用和人、狗、猪一样的方式调用cat1的talk方法,即func(cat1) '''
封装
封装,顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容。
所以,在使用面向对象的封装特性时,需要:
- 将内容封装到某处
- 从某处调用被封装的内容
在程序中:务必保证先定义类,后产生对象
这与函数的使用是类似的,先定义函数,后调用函数,类也是一样的,在程序中需要先定义类,后调用类
不一样的是,调用函数会执行函数体代码返回的是函数体执行的结果,而调用类会产生对象,返回的是对象