面向对象
面向对象编程(Object Oriented Programming,OOP,面向对象程序设计)
什么是面向对象?
面向对象就是一种使用'类'和'对象'进行编程的编程方式.
类是一个模板,模板里可以包含多个函数,类中定义的这些函数称为方法,对象就是根据模板创建的实例,通过实例对象可以执行类中的方法.
类的定义: class 类名: #定义了一个类 def 函数名(self) #在类中创建一个方法 pass 类的调用: x1 = 类名() #创建一个对象(实例化)一个对象 x1.函数名() #通过对象调用一个方法
class Foo: #创建一个类 def func(self): #创建一个类中的方法 print('这是一个类中的方法.') obj = Foo() #根据类创建一个叫做obj的对象 obj.func() #通过对象去使用方法 结果: 这是一个类中的方法.
注意:类中的方法的第一个参数必须是self.
面向对象与函数编程的区别:
面向对象: 创建对象-->通过对象执行方法
函数编程: 执行函数
函数编程的应用场景-->各个函数之间是独立的且无共用数据.
相较于函数编程,面向对象适用于共用数据的编程场景.
面向对象的三大特性: 封装,继承,多态
封装(将相关功能封装到一个类中, 将数据封装到一个对象中)
封装就是将内容封装到某个地方,以后再去调用被封装在某处的内容.在使用面向对象的封装特性时,需要:
将内容封装到某处
从某处调用封装的内容
将内容封装到某处
class Foo: def __init__(self, name, age): #构造方法,根据类创建对象时自动执行 self.name = name self.age = age obj = Foo('ZhangSan', 20) #根据类创建对象并自动执行类的__init__方法
self是一个形式参数,执行obj = Foo('ZhangSan', 20)是,self等于obj
此时,name和age被封装到对象obj中,可以理解为obj对象里面有name = 'ZhangSan'和age = 20两个变量.
从某处调用被封装的内容
在调用被封装的内容时,有两种情况:
1.通过对象直接调用
2.通过self间接调用
1.通过对象直接调用被封装的内容
class Foo: def __init__(self, name, age): #构造方法,根据类创建对象时自动执行 self.name = name self.age = age obj = Foo('ZhangSan', 20) #根据类创建对象并自动执行类的__init__方法 print(obj.name) print(obj.age) 结果: ZhangSan 20
2.通过self间接调用被封装的内容
class Foo: def __init__(self, name, age): #构造方法,根据类创建对象时自动执行 self.name = name self.age = age def detail(self): print(self.name) print(self.age) obj = Foo('ZhangSan', 20) #根据类创建对象并自动执行类的__init__方法 obj.detail() 结果: ZhangSan 20
将相关功能封装到一个类中.
class Message: def email(self):pass def msg(self):pass def wechat(self):pass
将数据封装到一个对象中.
class Person: def __init__(self, name, age, gender): self.name = name self.age = age self.gender = gender obj = Person('张三', 18, '男') print(obj.name) print(obj.age) print(obj.gender) 结果: 张三 18 男
写面向对象的两种小方式
1.归类+提取公共值
2.在指定类中编写和当前类相关的所有代码+提取公共值
1.归类+提取公共值
#归类 class File: def file_read(self, file_path): pass def file_update(self, file_path): pass def file_delete(self, file_path): pass def file_add(self, file_path): pass
#提取公共值 class File: def __init__(self,file_path): self.file_path = file_path def file_read(self): pass def file_update(self): pass def file_delete(self): pass def file_add(self): pass
2.在指定类中编写和当前类相关的所有代码+提取公共值
class Person: def __init__(self, na, gen, age, fig): self.name = na self.gender = gen self.age = age self.fight =fig def grassland(self): self.fight = self.fight - 10 def practice(self): self.fight = self.fight + 90 def incest(self): self.fight = self.fight - 666
继承
对面型对象来说,继承就是将多个类共有的方法提取到父类(基类)中,子类(派生类)只需要继承父类而不需要一一实现.
多继承提高了代码的重用性
class SuperBase: def f3(self): #注意:此处的self仍然是obj print('f3') class Base(SuperBase): # 父类,基类 def f2(self): #注意:此处的self仍然是obj print('f2') class Foo(Base): # 子类,派生类 def f1(self): #此处的self为obj print('f1') obj = Foo() #创建一个对象 obj.f1() #使用f1方法 obj.f2() #自己的类中没有,去Base类中找 obj.f3() #自己的类中没有,去Base类中找,Base中也没有,去SuperBase类中找 结果: f1 f2 f3
继承的原则:先在自己的类中找,没有就去父类中找.(注意:创建的对象不会变,调用这个对象,这个类中的self就一直是这个对象,self不会因为在父类中寻找而变成另外的对象.)
多继承
class Base1: def show(self): print('Base1.show') class Base2: def show(self): print('Base2.show') class Foo(Base1,Base2): pass obj = Foo() obj.show() 结果: Base1.show
多继承原则:先在自己的类中找,没有就去父类中找,(上面例子中,先到Base1中找,如果Base1中没有就去Base2中找)先从左边(离自己近的)的父类找.
1,多继承先找左边
2,self是哪个类的对象,就从哪个类开始找(自己的类中没有就去父类中找)
多继承顺序补充:
python2中类分为经典类和新式类
python3中只有新式类
class A: pass class B(A): pass class C(A): pass class D(B, C): pass obj = D() 结果: python2中:D,B,A,C python3中:D,B,C,A,object
上面代码中的类,在python2中都是经典类,经典类继承按照深度优先的顺序继承.
新式类:如果自己或者自己的祖辈继承了object,就是新式类.
class A(object): pass class B(A): pass class C(A): pass class D(B, C): pass obj = D() 结果: python2中:D,B,C,A,object python3中:D,B,C,A,object
class A:
pass
class B(A):
pass
class C(A):
pass
class D(B, C):
pass
obj = D()
结果:
python3中:D,B,C,A,object
class A(object):
pass
class B(A):
pass
class D(object):
pass
class C(B, D):
pass
class E(object):
pass
class F(E):
pass
class G(D, F):
pass
class H(C, G):
pass
obj = H()
结果:
继承顺序:H,C,B,A,G,D,F,E,object(下图)
python3中没有经典类,所有的类都是新式类,默认继承object类
在第二段代码中,class A默认继承了object.新式类的继承顺序按照c3算法.
多态
多种形态或多种状态(鸭子模型)
python原生支持多态,没有特殊性
class Foo1: def f1(self): #这里的self传入的参数可以是str,int,dict,list,tuple,set等数据类型 pass def func(arg): #这里的arg传入的参数可以是str,int,dict,list,tuple,set等数据类型 arg.f1()
这种对于传入参数的数据类型的不确定称为多态(在java等语言中,传入的数据类型是确定的)