Python基础(面向对象之封装与继承)
代码的编写一般分为三个阶段:
1、面向过程编程
针对具体需求的逻辑从上到下实现功能,当逻辑中出现重复的功能,采用的就是复制粘贴代码的方式来实现。
2、函数式编程
将需求中重复的功能封装到一个函数中,当逻辑中需要用到时则调用该函数,而无需重复编写。
3、面向对象编程
Python中一切都是对象,而对象是基于类创建的,根据类创建对象的过程叫实例化,被创建的对象又叫实例,具体到怎么实现Python的面向对象编程。简单的解释就是:
先定义一个类,然后在类中定义不同的方法(函数),不同的方法之间可以共用一组变量,然后根据这个类创建对象,被创建的对象就可以使用类中的方法。
Python面向对象具有以下特性:
1、封装
简单解释:隐藏对象所使用方法的具体细节。
普通解释:在由类创建对象时,每个被创建的对象中都有一个类对象指针,指向创建它的类,对象所使用的方法全部保存在类当中,类中的方法在执行的时候,需要使用的变量保存在对象中,这样对象所使用的方法对对象来说就是隐藏的,对象只能使用而不能修改这些方法。
详细解释:
class Person: #class是语法关键字 Person是类的名称
def __init__(self,name): #构造方法,根据类创建对象时自动执行
self.name = name #构造普通字段(变量),具体意思后面会解释
print 'Name is:%s'%self.name
def say(self): #定义一个方法,参数self为必填,且不能改变
print 'Name Say:%s'%self.name
p1 = Person('zhangsan') #根据Person类创建一个p1对象,在创建的时候会自动执行Person类中的__init__方法将传入的参数zhangsan封装到p1的name属性中,也就是p1.name='zhangsan'。同时会自动生成一个隐藏的类对象指针指向Person类,用来标示p1是由Person类创建的。
p1.say() #执行p1的say方法,这时p1本身是没有say方法的,它会根据类对象指针来找到用来创建它的Person类,然后执行Person类中的say方法,say方法需要用到self.name变量,这个变量是保存在对象本身中的,也就是self.name=p1.name,而p1.name在创建p1时已经构造完成,p1.name='zhangsan'
p2 = Person('lisi') #根据Person类创建一个p2对象,在创建的时候会自动执行Person类中的__init__方法将传入的参数zhangsan封装到p2的name属性中,也就是p2.name='lisi'。同时会自动生成一个隐藏的类对象指针指向Person类,用来标示p2是由Person类创建的。
p2.say() #执行p2的say方法,这时p2本身是没有say方法的,它会根据类对象指针来找到用来创建它的Person类,然后执行Person类中的say方法,say方法需要用到self.name变量,这个变量是保存在对象本身中的,也就是self.name=p2.name,而p2.name在创建p2时已经构造完成,p2.name='lisi'
执行结果:
Name is:zhangsan
Name Say:zhangsan
Name is:lisi
Name Say:lisi
以上例子的语法很简单,比较绕的可能就是一个self。封装的重点和难点也就在这个self,下面来具体解释这个self的意义:
面向对象中同一个类可以创建多个对象,这些对象所具有的方法都是来自于创建他们的类(对照上述例子中的say方法)。
那么问题来了:多个对象调用的都是同一个类中的同一个方法,那么方法在执行的时候是怎么区分是谁在调用它呢?怎么知道self.name的值该是什么呢?
这就是self的用处所在:在使用类创建对象的时候,会自动把对象的名称赋值给类中的self参数。
比如:
p1 = Person('zhangsan') #使用Person类创建一个名称叫p1的对象。这时Person类中的__init__方法将会被执行,执行过程就是:
def __init__('p1','zhangsan'):
p1.name = 'zhangsan'
print 'Name is:%s'%p1.name
#当执行p1.say()方法时,执行过程是:
def say('p1'):
print 'Name Say:%s'%p1.name
#其实相当于执行 Person.say('p1')
总结:对象在调用类方法的时候,对象是谁,那么方法中self的值就是谁。(self本质就是一个形式参数)
2、继承
简单解释:派生类(子类)继承基类(父类)的方法。(子承父业)
普通解释:Python中支持多继承(一个类可以继承多个类),当类是经典类的时候,如果继承的方法重复则广度优先(先横着找),当类是新式类的时候,如果继承的方法重复则深度优先(先竖着找)。
经典类和新式类的区别就是在定义的时候,新式类会继承object,如果一个类继承的父类是新式类,那么他也是新式类。这里我们不过多的去解释新式类和经典类在继承上的区别,因为容易把自己绕晕,记住新式类的继承规则就可以了。
详细解释:
class D(object): #定义一个新式类D
def f1(self): #在类中定义一个f1方法
print 'D:f1'
class C(D): #定义一个类C,继承类D
def f1(self): #在类中也定义一个f1方法
print 'C:f1'
class B(D): #定义一个类B,继承类D
pass #不定义任何方法
class A(B,C): #定义一个类A,同时继承类B和C
pass #不定义任何方法
obj = A() #根据类A创建对象
obj.f1() #执行f1方法
执行结果:
C:f1
上面程序的执行过程如下:
由于类D继承了object,所以它是一个新式类。C继承了D,所以C也是新式类,B也一样。A继承了B和C,所以A也是新式类。
对象obj执行f1方法,根据新式类继承的查找原则,顺序如下:
第一步:去A中查找f1方法,未找到。
第二步:去B中查找f1方法,未找到。
这里虽然B继承了D的f1方法,但是由于新式类是先横着查找,所以不会执行D中的f1方法
第三步:去C中查找f1方法,找到,然后执行,所以结果是C:f1。
继承中的其他需求用法:
如果在继承的时候同时希望使用基类(父类)中的字段(变量),该如何实现:
class Person:
def __init__(self,name):
print 'Person build self.name'
self.name = name
def say(self):
print 'Person.say'
class Son(Person): #定义一个类继承Person类
def __init__(self,name,age):
Person.__init__(self,name) #执行父类中的构造方法
print 'Son build self.age'
self.age = age
print 'Person name is %s age is %s'%(self.name,self.age)
p1 = Son('lily',17)
p1.say()
执行结果:
Person build self.name
Son build self.age
Person name is lily age is 17
Person.say
下一篇再介绍类的成员和类成员修饰符。
转载于:https://blog.51cto.com/rmeos/1719794