面向对象编程,是大多数高级语言都具有的程序设计思想,python 也不例外。面向对象主要体现为以下三点特性:
- 封装
- 多态
- 继承
在python语言中,面向对象最重要的两个概念为 类(class)和实例(instance).
定义类的关键字为class,这与大多数编程语言类似,class后接类名,类名后紧接着父类名称,如果没有继承类,则使用object类。定义类如下:
class Classname(object):
创建实例是通过类名实现的,例如:
class1=Classname() #变量class1 指向了一个Classname的实例
封装
在python 类定义中,也可以使用“构造函数”功能,通过定义一个特殊的 _ init _方法,第一个参数永远是 self,表示创建的实例本身。
有了_ init _方法,创建实重点内容例的时候,必须传入参数。例如:
class a(object):
def __init__(self,name):
self.name=name
stu=a('hello')
stu.name # 输出为 hello
访问限制,python语言中,如果需要对类中的变量进行作用域限定,即限定内部属性不被外部访问,可以在属性的名称前加两个下滑线 __
。一旦在类中的变量名前加入 __
,则声明了变量为类的私有变量,只能在内部进行访问,不能外部访问。
例如:
class a(object):
def __init__(self,name):
self.__name=name
def printa(self):
print(self.__name)
stu=a('zxg')
print(stu.__name) #会报错,错误类型AttributeError: 'a' object has no attribute '__name'
通过这种方式,就有效地保护了类对象内部的属性安全,如果需要获取类的私有变量的值,或者外部改变内部成员变量,只需要在类内部,增加如下的方法即可,
class a(object):
def __init__(self,name):
self.__name=name
def printa(self):
print(self.__name)
def get_name(self):
return self.__name
def set_name(self,name):
self.__name=name
stu=a('zxg')
a_name=stu.get_name() #变量a_name 存储了self.__name的值
stu.set_name('a') #变量self.__name值已经更新为 ‘a’
虽然使用__
变量,无法直接从外部访问变量,但是这是python解释器将变量重名的原因,拿上面的例子而言,python解释器将__name
对外显示为_a__name
,所以使用stu.__name
获取变量值,但是如果使用stu._a__name
,则有可能获取内部变量的值,为什么这里使用有可能?因为不同的python解释器,对类内部变量的重命名规则不同,因此,强烈建议不要这样访问内部变量。
继承
面向对象程序设计,继承使用广泛,简单地说,当我们定义一个类,如果这个类需要继承某个现有的类,则把新产生的类称为子类,被继承的类称为父类或者基类。
举个例:
class student(object): #基类
def p_info(self):
print('I am student!')
class mid_student(student): #初中学生子类,继承student
pass
class high_student(student):#高中学生子类,继承student
pass
子类可以继承父类的全部功能,使用如下:
a=mid_student()
a.p_info() # 输出 I am student!
b=high_student()
b.p_info() #输出 I am student!
当然,也可在子类中继续增加方法,
class mid_student(student):
def p_info(self):
print('I am mid_student!') #函数名与父类函数名一致,因此调用时,会覆盖父类函数
def p_act(self):
print ('More homework!!!')
调用后,结果如下:
a=mid_student()
a.p_info() # 输出 I am mid_student!
a.p_act() #输出 More homework!!!
如上,当子类的函数覆盖父类的函数时,代码运行时,总是会调用子类的函数功能,这样,就体现了 面向对象程序设计的另一特性:多态。
多态
子类继承父类 ,任何依赖父类作为参数的函数都可以不加修改地正常运行, 运行时由该对象的确切类型决定。
class student(object):
def p_info(self):
print('I am student!!')
class mid_student(student):
def p_info(self):
print('I am mid_student!')
def p_act(self):
print ('More homework!!!')
def p_info_twice(student): # 参数为父类
student.p_info()
student.p_info()
class high_student(student):#高中学生子类,继承student
#def p_info(self):
# print('I am high_student!')
def pp(mid_student):
mid_student.p_info()
a=mid_student()
a.p_info_twice() #自动调用 mid_student类型的p_info方法
#输出 I am mid_student!
I am mid_student!
b=high_student()
b.pp()
#输出 I am student!!
# high_student继承的是student不是mid_student,因此 pp方法的mid_student类型,会逐一向上寻找,找到父类student的p_info方法