类
面向对象
面向对象程序设计具有三大基本特征:封装、继承和多态,下面分别描述。
封装
封装是面向对象编程的核心思想,将对象的属性和行为封装起来,而将对象的属性和行为封装起来的载体就是类,类通常对客户隐藏其实现细节,这就是封装的思想。
采用封装思想保证了类内部数据结构的完整性,使用该类的用户不能直接看到类中的数据结构,而只能执行类允许公开的数据,这样就避免了外部对内部数据的影响,提高了程序的可维护性。
为什么要封装
封装数据的主要原因是:保护隐私
在python中用双下划线的方式实现隐藏属性(设置成私有的)
类中所有双下划线开头的名称如__x都会自动变形成:_类名__x的形式:
class A:
__N=0 #类的数据属性就应该是共享的,但是语法上是可以把类的数据属性设置成私有的如__N,会变形为_A__N
def __init__(self):
self.__X=10 #变形为self._A__X
def __foo(self): #变形为_A__foo
print('from A')
def bar(self):
self.__foo() #只有在类内部才可以通过__foo的形式访问到.
这种自动变形的特点:
类中定义的__x只能在内部使用,如self.__x,引用的就是变形的结果。
这种变形其实正是针对外部的变形,在外部是无法通过__x这个名字访问到的。
在子类定义的__x不会覆盖在父类定义的__x,因为子类中变形成了:_子类名__x,而父类中变形成了:_父类名__x,即双下滑线开头的属性在继承给子类时,子类是无法覆盖的。
# -*- coding: utf-8 -*-
class C: #正常情况
def fa(self): # 在定义时就变形为_A__fa
print('from A')
def test(self):
self.fa() # 只会与自己所在的类为准,即调用_A__fa
class B(C):
def fa(self):
print('from B')
b=B() #在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的
b.test()
输出:
from B
# -*- coding: utf-8 -*-
class C: #把fa定义成私有的,即__fa
def __fa(self): # 在定义时就变形为_A__fa
print('from A')
def test(self):
self.__fa() # 只会与自己所在的类为准,即调用_A__fa
class B(C):
def __fa(self):
print('from B')
b=B() #在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的
b.test()
输出:
from A
@property的用法
class Rectangle:
@property
def width(self):
# 变量名不与方法名重复,改为true_width,下同
return self.true_width
@property
def height(self):
return self.true_height
s = Rectangle()
# 与方法名一致
s.width = 1024
s.height = 768
print(s.width, s.height)
此时,如果在外部想要给width重新直接赋值就会报AttributeError: can't set attribute的错误,这样就保证的属性的安全性。
同样为了解决对属性的操作,提供了封装方法的方式进行属性的修改
class Rectangle(object):
@property
def width(self):
# 变量名不与方法名重复,改为true_width,下同
return self.true_width
@width.setter
def width(self, input_width):
self.true_width = input_width
@property
def height(self):
return self.true_height
@height.setter
#与property定义的方法名要一致
def height(self, input_height):
self.true_height = input_height
s = Rectangle()
# 与方法名一致
s.width = 1024
s.height = 768
print(s.width,s.height)
此时就可以对“属性”进行赋值操作
继承
继承是实现重复利用的重要手段,子类通过继承复用了父类的属性和行为的同时,又添加了子类的特有属性和行为。
为什么要继承
减少代码冗余、提高重用性
单继承
class grandFather():
print('我是爷爷')
class Parent(grandFather):
print('我是父类')
class SubClass(Parent):
print('我是子类')
sub = SubClass()
#结果: 我是爷爷
# 我是父类
# 我是子类
#注意:类在定义的时候就执行类体代码,执行顺序是从上到下
属性查找顺序
对象查找属性的顺序:对象自己的 - > 所在类中 -> 找父类 - >父类的父类 ->Object
覆盖
也称之为重写 overrides
当子类出现了与父类名称完全一致的属性或是方法