面向对象编程
虽然Python是解释性语言,但是它是面向对象的,能够进行对象编程。下面就来了解一下如何在Python中进行对象编程。
一.如何定义一个类
在进行python面向对象编程之前,先来了解几个术语:类,类对象,实例对象,属性,函数和方法。
类是对现实世界中一些事物的封装,定义一个类可以采用下面的方式来定义:
class className:
block
注意:类名后面是冒号在block块里面可以定义属性和方法。
当一个类定义完之后,就产生了一个类对象
类对象的两种操作:引用:-----通过类对象去调用类中的属性或方法。
实例化:-----产生出一个类对象的实例化例如:一个people类。
面向过程的程序设计的核心是过程(流水线式思维),过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西。
优点是:极大的降低了写程序的复杂度,只需要顺着要执行的步骤,堆叠代码即可。
缺点是:一套流水线或者流程就是用来解决一个问题,代码牵一发而动全身。
应用场景:一旦完成基本很少改变的场景,著名的例子有Linux內核,git,以及Apache HTTP Server等。
面向对象的程序设计的核心是对象(上帝式思维),要理解对象为何物,必须把自己当成上帝,上帝眼里世间存在的万物皆为对象,不存在的也可以创造出来。面向对象的程序设计好比如来设计西游记,如来要解决的问题是把经书传给东土大唐,如来想了想解决这个问题需要四个人:唐僧,沙和尚,猪八戒,孙悟空,每个人都有各自的特征和技能(这就是对象的概念,特征和技能分别对应对象的属性和方法),然而这并不好玩,于是如来又安排了一群妖魔鬼怪,为了防止师徒四人在取经路上被搞死,又安排了一群神仙保驾护航,这些都是对象。然后取经开始,师徒四人与妖魔鬼怪神仙互相缠斗着直到最后取得真经。如来根本不会管师徒四人按照什么流程去取。
面向对象的程序设计的
优点是:解决了程序的扩展性。对某一个对象单独修改,会立刻反映到整个体系中,如对游戏中一个人物参数的特征和技能修改都很容易。
缺点:可控性差,无法向面向过程的程序设计流水线式的可以很精准的预测问题的处理流程与结果,面向对象的程序一旦开始就由对象之间的交互解决问题,即便是上帝也无法预测最终结果。于是我们经常看到一个游戏人某一参数的修改极有可能导致阴霸的技能出现,一刀砍死3个人,这个游戏就失去平衡。
应用场景:需求经常变化的软件,一般需求的变化都集中在用户层,互联网应用,企业内部软件,游戏等都是面向对象的程序设计大显身手的好地方。
在python 中面向对象的程序设计并不是全部。
面向对象编程可以使程序的维护和扩展变得更简单,并且可以大大提高程序开发效率 ,另外,基于面向对象的程序可以使它人更加容易理解你的代码逻辑,从而使团队开发变得更从容。
了解一些名词:类、对象、实例、实例化
类:具有相同特征的一类事物(人、狗、老虎)
对象/实例:具体的某一个事物(隔壁阿花、楼下旺财)
实例化:类——>对象的过程(这在生活中表现的不明显,我们在后面再慢慢解释)
二:初识面向对象
python中一切皆为对象,类型的本质就是类。
在python中,用变量表示特征,用函数表示技能,因而具有相同特征和技能的一类事物就是类,对象则是这一类事物中具体的一个。
三:初识类
def functionName(args): '函数文档字符串' 函数体 '''class 类名: '类的文档字符串' 类体'''#我们创建一个类class Data: passclass Person: #定义一个人类 role = 'person' #人的角色属性都是人 def walk(self): #人都可以走路,也就是有一个走路方法,也叫动态属性 print("person is walking...")
类有两种作用:属性引用和实例化
属性引用(类名,属性)
class Person: #定义一个人类 role= 'Person' #人的角色属性都是人 def walk(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...')print(Person.role)print(Person.walk)
类属性的补充
一:我们定义的类的属性到底存到哪里了?有两种方式查看dir(类名):查出的是一个名字列表类名.__dict__:查出的是一个字典,key为属性名,value为属性值二:特殊的类属性类名.__name__# 类的名字(字符串)类名.__doc__# 类的文档字符串类名.__base__# 类的第一个父类(在讲继承时会讲)类名.__bases__# 类所有父类构成的元组(在讲继承时会讲)类名.__dict__# 类的字典属性类名.__module__# 类定义所在的模块类名.__class__# 实例对应的类(仅新式类中)
对象的相关知识
lass Person: # 定义一个人类 role = 'person' # 人的角色属性都是人 def __init__(self, name, aggressivity, life_value): self.name = name # 每一个角色都有自己的昵称; self.aggressivity = aggressivity # 每一个角色都有自己的攻击力; self.life_value = life_value # 每一个角色都有自己的生命值; def attack(self,dog): # 人可以攻击狗,这里的狗也是一个对象。 # 人攻击狗,那么狗的生命值就会根据人的攻击力而下降 dog.life_value -= self.aggressivit
定义及调用的方法
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 #查看对象的属性,直接用 对象名.属性名 即可对象名.方法名() #调用类中的方法,直接用 对象名.方法名() 即可
对象之间的交互
-------------------------------------------正方形-----------------------------------------------------------------------# class square: #定义一个正方形类# def __init__(self,length_of_side): #self实例化对象,__init__方法传入边长参数# self.length_of_side = length_of_side #将length_of_side赋值给边长# def perimeter(self): #定义一个周长方法# return self.length_of_side * 4 #计算周长并返回# def acreage(self):# return self.length_of_side * self.length_of_side#定义一个面积# a = square(10) #实例化,类名+括号就是实例化一个类,相当于调用了__init__方法# # 括号里传参数,参数不需要传self,其他与init中的形参一一对应# #结果返回一个对象# print(a.perimeter()) #打印# print(a.acreage())#----------------------------------------------------圆----------------------------------------------------------------class circle: #定义一个圆类 def __init__(self,radius,m=3.14): #实例化对象,__init__方法传入边长参数 self.radius = radius #赋值变长 self.m = m #赋值幂 def proportion(self): #定义面积方法 return self.m * self.radius * self.radius def perimeter(self): #定义周长方法 return self.radius * 2 * self.mp = circle(10) #实例化print(p.proportion())print(p.perimeter())
组合:组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合
class Course:# def __init__(self,name,period,price):# self.name = name# self.period = period# self.price = price# class Brith:# def __init__(self,year,month,day):# self.year = year# self.month = month# self.day = day# class Teacher:# def __init__(self,name,salary,bf,course_name,course_period,course_price):# self.name = name# self.salary = salary# self.bf = bf# self.course = Course(course_name,course_period,course_price)# egg = Teacher('egon','200','yuan','python','6',20000000)# print(egg.bf)# print(egg.course.name)# print(egg.name)# print(egg.course.price)# egg_brith = Brith(1965,2,2)# print(egg_brith.year)# egg.brith = egg_brith# print('******',egg.brith.year)
继承:
在继承中: 继承的语法:class 类名(父类名) 如果不指定,默认object 如果想在子类中调用父类的方法: 在类中-----super(子类名,self).方法名() 在类外-----super(子类名,对象名).方法名() 如果子类有的方法就执行子类的, 如果子类没有就执行父类的, 如果子类父类都没有报错。 继承:大范围---小
class Animal: #父类 基类 超类# def __init__(self,name,life_value,aggr):# self.name = name# self.life_value = life_value# self.aggr =aggr# class Person(Animal):#子类 派生类# pass# class Dog(Animal):#子类 派生类# pass# egg = Person('egon',1000,50)# print(Person.__bases__)#__bases__------------------查看继承----尽量少用多继承__# class Foo:pass# class Mu:pass# class Son1(Foo,Mu):pass# class Son2(Foo,Mu):pass# print(Son1.__bases__)# print(Foo.__bases__)#------默认继承object#-----------抽象----------------------------------#抽象:提取一类事物的特点# 范围越来越大,共性越来越少。#属性:#方法:#继承:继承是基于抽象的结果。
#---------------集成进阶---------------------------# class Pet:# def eat(self):# pass## def sleep(self):# pass## def drink(self):# pass# class Cat(Pet):# def catch(self):# pass# class Dog(Pet): #Pet类的派生类,也叫子类# def wtch_door(self): #Pet类的派生方法# pass#从上到下叫继承,从下倒上叫抽象
派生:
派生:就是在父类的基础上产生子类的方法-----派生类 派生方法:父类里没有,子类有 派生属性:父类里没有,子类有
class Animal: #父类 基类 超类# def __init__(self,name,life_value,aggr):# self.name = name# self.life_value = life_value# self.aggr =aggr# def eat(self):# self.life_value+=10# class Person(Animal):#子类 派生类# def attack(self,enemy):#人的派生方法# enemy.life_vale = enemy.life_vale-self.aggr# enemy.life_vale-=self.aggr# class Dog(Animal):#子类 派生类# def __init__(self,br):# def bit(self,person):#狗的派生方法# person.lift_vale-=self.aggr# egg = Person('egon',1000,50)# # print(Person.__bases__)#---查看继承# ha2 = Dog('晚才',20000,5000)#实例化狗# eg = Person('egon',1000,50)#实例化人# print(egg.aggr)# print(ha2.aggr)# print(egg.life_value)# egg.eat()# print(egg.life_value)# ha2.eat()# print(ha2.life_value)
派生的重写:父类里有的,在子类里重新实现。
# print(ha2.life_value)--------------------重写-----------------------# class Animal: #父类 基类 超类# def __init__(self,name,life_value,aggr):# self.name = name# self.life_value = life_value# self.aggr =aggr# def eat(self):# self.life_value+=10# class Person(Animal):#子类 派生类# def __init__(self,money):# self.money = money# def attack(self,enemy): #人的派生方法# enemy.life_vale = enemy.life_vale-self.aggr# enemy.life_vale-=self.aggr# class Dog(Animal): #子类 派生类# def __init__(self,brccd,name,life_value,aggr):# super().__init__(name,life_value,aggr)#super关键字.父类的方法 新式类# # Animal.__init__(self,name,life_value,aggr)#让子类执行父类的方法,就是父类名.方法名(参数),self也传。# self.brccd = brccd# def bit(self,person):#-----------------------狗的派生方法# person.lift_vale-=self.aggr# def eat(self):#------------------------父类方法的重写# super().eat()#---------------------重定方法# print("--------------------------------->")# ha2= Dog('刘','wan',20000,1000)# # print(ha2.life_value)# print(ha2.life_value)# egg = Person('egon',1000,50)# print(Person.__bases__)#---查看继承# ha2 = Dog('晚才',20000,5000)#实例化狗# eg = Person('egon',1000,50)#实例化人# print(egg.aggr)# print(ha2.aggr)# print(egg.life_value)# egg.eat()# print(egg.life_value)# ha2.eat()# print(ha2.life_value)
总结:
在继承中: 继承的语法:class 类名(父类名) 如果不指定,默认object 如果想在子类中调用父类的方法: 在类中-----super(子类名,self).方法名() 在类外-----super(子类名,对象名).方法名() 如果子类有的方法就执行子类的, 如果子类没有就执行父类的, 如果子类父类都没有报错。 继承:大范围---小 抽象:小------大 派生:就是在父类的基础上产生子类的方法-----派生类 派生方法:父类里没有,子类有 派生属性:父类里没有,子类有 派生的重写:父类里有的,在子类里重新实现。 抽象类与接口类 接口类:继承有两种用途: 一:继承基类的方法,并且做出自己的改变或者扩展(代码重用) 二:声明某个子类兼容于某基类,定义一个接口Interface,接口类中定义了一些接口名(就是函数名),并且未实现接口的功能, 子类继承接口类,并且实现接口中的功能。
约束继承接口类的子类必须实现被abstracmethod的方法 在接口类中不要做实现 接口类不能做实例化
from abc import ABCMeta,abstractmethod# class Payment(metaclass = ABCMeta):# @abstractmethod# def pay(self,money):pass# class Appleay(Payment):# def pay(self,money):# print('apple pay 支付%s'%money)# class Alipay(Payment):# def pay(self,money):# print('支付宝 支付了%s'%money)# class Wechatpay(Payment):# def pay(self,money):# print('微信 支付了%s'%money)# def payment(pay_onj,money):# pay_onj.pay(money)# applel = Appleay()# applel.pay(200)# alil= Alipay# alil.pay(400)
实践中,继承的第一种含义意义并不很大,甚至常常是有害的。因为它使得子类与基类出现强耦合。
继承的第二种含义非常重要。它又叫“接口继承”。
接口继承实质上是要求“做出一个良好的抽象,这个抽象规定了一个兼容接口,使得外部调用者无需关心具体细节,可一视同仁的处理实现了特定接口的所有对象”——这在程序设计上,叫做归一化。归一化使得高层的外部使用者可以不加区分的处理所有接口兼容的对象集合——就好象linux的泛文件概念一样,所有东西都可以当文件处理,不必关心它是内存、磁盘、网络还是屏幕(当然,对底层设计者,当然也可以区分出“字符设备”和“块设备”,然后做出针对性的设计:细致到什么程度,视需求而定)。
#抽象类:从小范围到大范围# from abc import ABCMeta,abstractmethod# class Animal(metaclass=ABCMeta):# def eat(self):pass# @abstractmethod# def sleep(self):pass# class Dog(Animal):# def eat(self):# super().eat()# print('dog is eating')# def sleep(self):# print('dog is sleeping')#当几个子类的父类 有相同的功能需要被实现的时候---抽象类#当几个子类 有相同的功能 但是实现各不相同的时候---接口类#约束#接口类和抽象类在java里面的区别#接口类支持多继承#抽象类只支持单继承
class Animal:# def swin(self):pass# def fil(self):pass# def walk(self):pass# class Dog(Animal):pass# class Parmsk(Animal):pass#接口类:# 在python里 默认是没有的# 方法不能被实现#抽象类:# 默认是有的# 父类方法,子类必须实现# 抽象类不能被实例化# 抽象类的方法 可以被简单实现#原则:抽象类里最好不要用多继承,接口可以# from abc import ABCMeta,abstractmethod# class Acjnn_swwing(metaclass=ABCMeta):# def jncs(self):pass# class jnjncjn_wamm# class A:# 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,C):# def test(self):# print('from D')# print(D.mro())# d = D()# d.test()#新式类:广度优先#经典类:深度优先
多态:态指的是一类事物有多种形态
静态多态性 序列: python自带多态 1:同一种事物的不同状态 2:操作的时候不需要关心
class A: def bhsbc(self): print('----A----')class B(A): def dkdmvkm(self): print('------B-----')class C(A): def dbu(self): print('-------C-------')w = C()w.bhsbc()#静态多态性#序列:#python自带多态#1:同一种事物的不同状态#2:操作的时候不需要关心