Python面向对象


Python面向对象

我们前面介绍的数据结构和运算都是面向过程的,而Python本身设计之初就是面向对象的编程语言,本节我们学习Python中的面向对象编程。

面向过程VS面向对象

面向过程是以事件为中心的编程思想,按照完成这件事需要的所有步骤,强调按部就班,一个函数一个函数、一个语句一个语句的顺序执行。

以下五子棋为例,一个下五子棋的面向过程程序大约需要以下步骤:

  1. 开始游戏;
  2. 黑子先行,绘制黑子落子后的画面;
  3. 判断输赢情况,如果黑子赢了就跳到最后一步;
  4. 白子再行,绘制白子落子后的画面;
  5. 判断输赢情况,如果白子赢了就跳到最后一步;
  6. 返回第二步;
  7. 输出最后结果。

而面向对象的五子棋程序会首先设计三种互相独立的对象:

  1. 棋手,包括黑子和白子,负责接收用户的输入,并告知棋盘系统棋子布局的变化;
  2. 棋盘系统,负责接收棋手传递的用户落子情况,然后绘制画面,在屏幕显示;
  3. 游戏规则,负责根据棋盘情况判定输赢。

看起来没有太大区别,只是对面向过程的内容做了一些封装,然而如果我们要写的代码是运行一个公司呢?每个行为方的行为规则和和属性可能都复杂到面向过程难以描述,描述了别人也难以快速看懂、快速修改和扩展。

面向对象的编程极大提高了代码的可扩展性和复用性,降低了维护难度,在写一些大型的工程时具有很明显的优势,二者对比如下表。

面向过程 面向对象
高耦合 低耦合
高效率,低开销,低可读性 低效率,高开销,高可读性
难维护,难扩展 易维护,易扩展

面向对象简介

面向对象技术中主要有以下几个概念:

  • 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法;
  • 对象(Object):是类的实例;
  • 方法:类中定义的函数;
  • 实例变量:实例变量指的是在任意类方法内部,以“self.变量名”的方式定义的变量,其特点是只作用于调用方法的对象。另外,实例变量只能通过对象名访问,无法通过类名访问;
  • 类变量:类变量指的是在类中,但在各个类方法外定义的变量,所有类的实例化对象都同时共享类变量,可以通过类名或者对象名进行访问;
  • 保护:包括保护变量和保护方法。以单下划线开头,表示被保护的变量和方法只允许类及其子类使用,在使用中与普通变量没什么区别;
  • 私有:包括私有变量和私有方法。私有变量和私有方法只有类中定义的方法可以访问,子类不可以访问;
  • 实例化:创建一个类的实例,类的具体对象;
  • 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。

我们来定义一个简单的类:

class People:

    # id 是一个普通的类变量
    id = 1
    # 单下划线开头的是保护变量,_protected1是受保护的类变量
    # 保护变量表示只允许类及其子类使用,然而在使用中与普通变量没什么区别
    _protected1 = 2
    # 双下划线开头的是私有变量,__private1是私有的类变量
    # 私有变量只有类中定义的方法可以访问,子类不可以访问
    __private1 = 3

    # __init__()是类的构造函数,实在一个类进行实例化的时候自动调用的函数,可以传入参数
    # 以双下划线开头且以双下划线结尾的函数在Python中表示特殊功能的函数,我们在写代码时尽量不要写这种形式的函数名
    def __init__(self, para1, para2):
        # name gender 是实例变量
        self.name = para1
        self.gender = para2
        # _protected2是受保护的实例变量
        self._protected2 = True
        # __private2是私有的类变量
        self.__private2 = True

    # 类中的一个方法,类中定义的方法的参数都必须包含self且以self开头
    # self表示的是实例化的对象
    def prtname(self):
        print(self.name)

    # 类中的一个方法
    def prtgender(self):
        print(self.gender)

    # 私有变量只有类中定义的方法可以访问1
    def prtprivate(self):
        print(self.__private1)
        print(self.__private2)

    def _prtgender(self):
        print(self.gender)

    def __privatefunc(self):
        print(self.__private1)
        print(self.__private2)

# 实例化People类,得到一个对象x
x = People("gs", "1")

# 调用类变量可以通过对象和类
print(People.id)
print(People._protected1)
# 下面注释掉的几句是错误的
# print(People.__private1)
# print(People.name)
# print(People.gender)
# print(People._protected2)
# print(People.__private2)

print(x.id)
print(x._protected1)
print(x.name)
print(x.gender)
print(x._protected2)
# 下面注释掉的是错误的
# print(x.__private1)
# print(x.__private2)

# Python并没有从语法上严格保证私有属性或方法的私密性
# Python还提供了一种作弊的方法用于访问私有变量,Python寄希望于使用者自觉遵守规则并为自己的行为负责。
#“We are all consenting adults here”
print(x._People__private1)
print(x._People__private2)

# 调用类中的方法
x.prtname()
x.prtgender()

# private变量只有类中定义的方法可以调用
x.prtprivate()

这段代码的注释中基本写明了各种变量和函数的用法。下面我们学习继承的概念,帮助我们更好地理解类的用法。

类的继承

一个类可以继承另一个类,如类Student可以继承类People,此时Student称为子类,People称为父类。子类可以继承父类的普通变量与方法,以及保护变量与方法。

现在我们基于上一小节的代码继续往下写一个People类的子类Student,看看下面这段代码中,为什么有的调用正确,有的调用错误。

class Student(People):

    def __init__(self, para1, para2, para3):
        People.__init__(self, para1, para2)
        self.school = para3

s = Student("gs", "1", 3)

print(s.school)
print(s.id)
print(s._protected1)
print(s.name)
print(s.gender)
print(s._protected2)
s.prtname
s._prtgender()
s.prtprivate()
# 下面注释掉的几句是错误的
# print(s.__private1)
# print(s.__private2)
# s.__privatefunc()

当然,一个类可以有很多个子类,子类还可以有子类,可以无限继承下去。

一个子类也可以有多个父类,在初始化时需要对各个父类都做初始化。

另外如果子类中定义了与父类相同名称的函数,在子类的一个实例对象调用该函数时,就会优先调用子类中的该函数,这就是“多态”。即,对于父类的方法,一个子类可以做无限修改,而不影响其他子类,也不影响依赖于该父类和该方法的其他函数。

以一张图结束本节课程吧,不知道小仙女有没有懂那么一丢丢呀😄😄😄

面向对象


评论
  目录