面向对象编程简单来说就是基于对 类 和 对象 的使用,所有的代码都是通过类和对象来实现的编程就是面向对象编程!
面向对象的三大特性:封装、继承、多态
首先创建一个类
#使用class创建一个School类,类中有个student方法 class School: def student(self): pass a1=School()
一、封装
1、封装:将某些内容先封装到一个地方,等到需要的时候再去调用
class School: def __init__(self,name,age): #构造方法,创建对象是执行 self.name=name self.age=age #创建对象a1,a2 a1=School("zhangsan",18) a2=School("lisi",18)
上面代码实现的就是封装的功能,把各自的name和age分别封装到了self的name和age属性中,就等于被封装到了对象a1和a2中
类中定义的函数叫做方法,带有__init__的函数称为构造方法,在创建a1,a2对象时会自动执行。
2、调用:调用有两种方式,通过对象直接调用和通过self间接调用
通过对象直接调用
class School: def __init__(self,name,age): self.name=name self.age=age def student(self): print("name:%s,age:%s"%(self.name,self.age)) #创建对象a1,a2 a1=School("zhangsan",18) a2=School("lisi",18)
print a1.name,a1.age
print a2.name,a2.age
#执行结果: zhangsan 18
lisi 18
通过self间接调用
class School: def __init__(self,name,age): self.name=name self.age=age def student(self): print("name:%s,age:%s"%(self.name,self.age)) #创建对象a1,a2 a1=School("zhangsan",18) a2=School("lisi",18) #执行类中的方法时,通过self间接调用被封装的内容 a1.student() a2.student() #执行结果: #name:zhangsan,age:18 #name:lisi,age:18
二、继承
1、继承:既派生类(子类)可以继承基类(父类)的方法,我们可以将多个类共有的方法提取到父类当中,这样子类仅需继承父类而不必一一实现每个方法
在类名后面括号中写上另一个类,表示继承了那个类
#使用class创建一个School类 class School: def __init__(self,name,age): self.name=name self.age=age def student(self): print("name:%s,age:%s"%(self.name,self.age)) def classroom(self): print("%s去教室"%self.name) class SchoolA(School): #SchoolA继承School def __init__(self,name): self.name=name class SchoolB(SchoolA): #SchoolB继承SchoolA def __init__(self,name): self.name=name #创建对象a1 a1=SchoolA("zhangsan") a1.classroom() #创建对象a2 a2=SchoolB("lisi") a2.classroom() #执行结果: # zhangsan去教室 # lisi去教室
在上面代码中我们可以看到,在SchoolA和SchoolB中都没有classroom方法,但由于SchoolB继承了SchoolA,而SchoolA又继承了School,所以他们创建对象后都能
调用School中的classroom方法。
2、多继承
在python中,类还可以继承多个类,在继承多个类时,他对类中的函数查找有两种方式
深度优先:类是经典类时,多继承情况下,会按照深度优先方式查找
广度优先:类是新式类时,多继承情况下,会按照广度优先方式查找
(在python3.x中)都默认为广度优先,但还是可以了解一下两个的区别,新式类:当前类或者基类继承了objiect类就叫新式类,否者就是经典类
在python2.7中
#python2.7中经典类 class A(): def name(self): print("AAAAAA") class B(A): pass class C(A): def name(self): print("CCCCCC") class D(B,C): pass a1=D() a1.name() #输出:AAAAAA #查找顺序:# 首先去自己D类中查找,如果没有,则继续去B类中找,没有则继续去A类中找,没有则继续去C类中找,如果还是未找到,则报错 #深度优先:D-B-A-C
#python2.7中新式类 class A(object): def name(self): print("AAAAAA") class B(A): pass class C(A): def name(self): print("CCCCCC") class D(B,C): pass a1=D() a1.name() #输出:CCCCCC #查找顺序:# 首先去自己D类中查找,如果没有,则继续去B类中找,没有则继续去C类中找,没有则继续去A类中找,如果还是未找到,则报错 #广度优先:D-B-C-A
上面两个例子中我们可以看到,经典类和新式类输出的结果是不一样的,是因为他们的查找顺序不一样
python2.7中 广度优先的前提条件:D继承BC,BC又同时继承A,只有满足这个条件,新式类才会遵循广度优先,否者不会,例:
class A(object): def name(self): print("AAAAAA") class B(A): pass class C: def name(self): print("CCCCCC") class D(B,C): pass a1=D() a1.name() #输出:AAAAAA
如果C不在继承A,那么就算你是新式类,他也会按照深度优先的顺序查找
在python3.X之后就没有了上面的这些区别,它的查找顺序都是 广度优先
三、多态
python不支持多态,也用不到多态,python是一种多态语言,崇尚鸭子类型
四、类中的成员
类中的成员:字段、方法、属性
1、字段
字段:普通字段、静态字段
class School: headmaster="王五" def __init__(self,name,age): self.name=name self.age=age def student(self): print("name:%s,age:%s"%(self.name,self.age)) #创建对象a1 a1=School("zhangsan",18) print(a1.name) #访问普通字段 print(School.headmaster) #访问静态字段 #执行结果: # zhangsan # 王五
在上面代码中,__init__函数中的就是普通字段,headmaster就是静态字段
普通字段:属于对象,由对象来访问,在内存中每个对象都要保存一份
静态字段:属于类,由类直接访问,在内存中只保存一份
2、方法
方法:普通方法、静态方法、类方法
class School: headmaster="王五" def __init__(self,name,age): self.name=name self.age=age def student(self): #普通方法 至少一个self print("普通方法") @staticmethod #静态方法 任意参数 def classroom(): print("静态方法") @classmethod def dormitory(cls): #类方法 只能一个cls print("类方法",cls) #创建对象a1 a1=School("zhangsan",18) a1.student() School.classroom() #访问静态方法 School.dormitory() #访问类方法 '''执行结果: 普通方法 静态方法 类方法 <class '__main__.School'> '''
普通方法:先创建一个对象,在用对象去调用这个方法
静态方法:直接用类调用,可以有任意参数(静态方法可以让类直接调用,省去了普通方法创建对象的步骤)
类方法:直接用类调用,只能一个cls参数
上面我们可以看到执行类方法时,输出了他传入的参数等于<class '__main__.School'>,是一个类,意思就是执行时,它会把当前的类当成参数传进去。
3、属性
属性定义:装饰器定义、静态字段定义
(1)装饰器定义
class School: headmaster="王五" def __init__(self,name,age): self.name=name self.age=age def student(self): #方法 print("方法") @property def classroom(self): #属性,加上@property装饰器,仅有一个self参数 print("属性") #创建对象a1 a1=School("zhangsan",18) a1.student() #调用方法 a1.classroom #调用属性 #执行结果: # 方法 # 属性
在上面代码中可以看到,在方法上加上@property装饰器就叫属性,属性和方法的区别就是调用时不用加括号
在新式类中,除了@property,还有另外两种装饰器
class School(object): def __init__(self,name,age): self.name=name self.age=age @property def classroom(self): #属性,加上@property装饰器,仅有一个self参数 print(self.name,self.age) @classroom.setter def classroom(self,age): self.age=age #把age修改为传入的参数 print("修改",self.name,self.age) @classroom.deleter def classroom(self): del self.age #删除age print("删除",self.name,self.age) #创建对象a1 a1=School("张三",18) a1.classroom #1.执行后会自动调用@property方法 a1.classroom=20 #2.执行后会自动调用@classroom.setter的方法,并将20传给age参数 del a1.classroom #3.执行后会自动调用@classroom.deleter的方法 '''执行结果: 张三 18 修改 张三 20 在执行3时会报错,因为age已经在@classroom.deleter下面的方法里删除了,所以输出self.age时会出错 '''
(2)静态字段定义
class School(object): def __init__(self,name,age): self.name=name self.age=age def classroom(self): print(self.name,self.age) def classroom_update(self,age): self.age=age #把age修改为传入的参数 print("修改",self.name,self.age) def classroom_del(self): del self.age #删除age print("删除",self.name,self.age) obj=property(classroom,classroom_update,classroom_del) #静态字段方式定义属性 #创建对象a1 a1=School("张三",18) a1.obj #1.执行后会自动调用classroom方法 a1.obj=20 #2.执行后会自动调用classroom_update的方法,并将20传给age参数 del a1.obj #3.执行后会自动调用classroom_delr的方法
4、公有成员和私有成员
在类中的每一个成员都有两种形式:公有、私有
公有:都可以访问 私有:只有在类的内部可以访问
举几个例子
字段
class School(object): deg="狗" #公有静态字段 __cat="猫" #私有静态字段 def __init__(self,name,age): self.name=name #公有普通字段 self.__age=age #私有普通字段 def dormitory(self): print(self.__age) def cat(self): print(School.__cat) #创建对象a1 a1=School("张三",18) #访问普通字段 print(a1.name) #输出:张三 print(a1.age) #报错,提示没有age,因为age是私有字段,只能间接内部访问 a1.dormitory() #只能通过类内部访问私有字段 #访问静态字段 print(School.deg) #输出:狗 print(School.__cat) #报错 a1.cat() #输出:猫 可以间接通过内部的cat方法反问私有静态字段
方法
class School(object): def __init__(self,name,age): self.name=name self.__age=age def cat(self): #公有方法 print("cat") def __dog(self): #私有方法 print("dog") def doo(self): #内部访问私有方法 a1.__dog() #创建对象a1 a1=School("张三",18) a1.cat() #输出:cat a1.dog() #报错 a1.doo() #输出:dog 间接通过doo方法反问私有方法__dog
类中的其他成员也和上面的类似
如果想要强制访问私有字段,可以通过(对象._类名__私有字段名)访问,不建议强制访问私有成员。
5、类中的特殊成员
(1)__doc__
class School(object): """类的描述信息""" def __init__(self,name,age): self.name=name self.__age=age print(School.__doc__) #输出:类的描述信息
(2)__init__
在上面已经说过,在创建对象是自动执行
(3)__del__
当对象在内存中被释放时,自动触发执行
(4)__call__
在创建的对象后面加括号执行时,会自动执行类里的__call__方法
class School(object): def __call__(self, *args, **kwargs): print("触发__call__方法") a1=School() a1() #输出:触发__call__方法 School()() #输出:触发__call__方法
(5)__dict__
获取类或对象的所有成员
class School(object): """类的描述信息""" cat="猫" def __init__(self,name,age): self.name=name self.__age=age def dog(self): print("dog") print(School.__dict__) #获取类中的成员 a1=School("张三",18) print(a1.__dict__) #获取对象中的成员 ''' 输出: {'cat': '猫', '__init__': <function School.__init__ at 0x000000000226C950>, '__dict__': <attribute '__dict__' of 'School' objects>, '__weakref__': <attribute '__weakref__' of 'School' objects>, '__module__': '__main__', 'dog': <function School.dog at 0x000000000226CAE8>, '__doc__': '类的描述信息'} {'name': '张三', '_School__age': 18} '''
(6)__str__
没有__str__
class School(object): def __init__(self,name,age): self.name=name self.__age=age a1=School("张三",18) print(a1) #输出:<__main__.School object at 0x000000000222B278>
有__str__
class School(object): def __init__(self,name,age): self.name=name self.__age=age def __str__(self): return("print对象时的返回值") a1=School("张三",18) print(a1) #输出:print对象时的返回值
其他的特殊成员就不一一列举了,因为大多数情况下也不会用到
详细请看:http://www.cnblogs.com/wupeiqi/p/4766801.html