在Python世界中,所有东西都是面向对象,面向对象的概念已经倡导多年,最早的雏形源于1960年的Simula语言,它引入了”对象”(object)有关的概念。一直到20世纪70年代SmallTalk语言出现,它除了汇集Simula的特性之外,还引入了”消息”(message),于是第一个面向对象程序设计(Object-Oriented Programming,OOP)语言才真正诞生了。面向对象程序设计的重点是强调软件的可读性(Readability)、可重复实用性(Reusability)与扩展性(Extension)。

面向对象技术简介

  • 类(Class):用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
  • 方法:类中定义的函数
  • 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
  • 数据成员:类变量或者实例变量用于处理类及其实例对象的相关数据
  • 方法重写:如果从父类继承的方法不能满足子类的需要,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法重写。
  • 局部变量:定义在方法中的变量,只作用于当前实例的类
  • 实例变量:在类的声明中,属性是用变量来表示的,这种变量就称为实例变量,实例边框就是一个用self修饰的变量
  • 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟”是一个(is-a)”关系(例图,Dog是一个Animal)。
  • 实例化:创建一个类的实例,类的具体对象
  • 对象:通过类定义的数据结构实例。对象包含两个数据成员(类变量和实例变量)和方法。

1.认识面向对象

现在许多程序设计语言中让人津津乐道的创新功能就是“面向对象程序设计”,这也是程序设计领域的一大创新。因为在传统程序设计的方法中,主要以“结构化程序设计”为主,它的核心是“自上而下”于“模块化”的设计模式,也就是将整个程序需求自上而下、从大到小逐步分解成比较小的单元,或称为“模块”(module)。这样使得程序员可针对各个模块分别开发,不但减轻了设计者的负担,提高了程序的可读性,而且对于日后的维护也容易很多。不过问题也来了,在“结构化程序设计”中,每一个模块都有其特定的功能,主程序在组合每个模块后,完成最后要求的功能。一旦主程序要求功能变动,许多模块内的数据于程序代码都可能需要同步变动,这也正是“结构化程序设计”无法有效使用程序代码的主要原因。

1.1 类与对象

什么是对象(object)?

在现实生活中充满了各种形形色色的物体,每个物体都可视为一种对象,例如正在阅读的书是一个对象,手上的笔也是一个对象。

任何面向对象程序设计语言中,最基本的单元就是对象,面向对象程序设计模式就是将问题实体分解成一个或多个对象,再根据需求加以组合。这些对象都各自拥有状态(state,或称为特征、属性)和行为(behavior或称为方法)。状态代表了对象所属的特征,行为则代表对象所具有的功能,用户可根据对象的使用方法来操作对象,进而获取或改变对象的状态数据或信息。

由于对象并不会无端凭空产生,每一个对象在程序设计语言中的实现都必须通过类(class)来声明。简单来说,对象必须有一个可以依据的原型(Prototype),也就是创建一个具有相同特性和行为的对象集合。

1.2 面向对象的特点

在面向对象的世界中,是以各个对象自行分担的功能来产生模块化的,它基本上包含三个基本元素:数据抽象化(封装)、继承和多态(动态绑定).

封装

封装(Encapsulation)就是利用类来实现抽象数据类型(ADT)。类是一种用来具体描述对象状态与行为的数据类型,也可以看成是一个模型或蓝图,按照这个模型或蓝图所产生的实例(Instance)就被称为对象。

所谓抽象,就是代表事物特征的数据隐藏起来,并定义一些方法作为操作这些数据的接口,让用户只接触到这些方法,而无法直接使用数据,也符合信息隐藏的要求,而这种定义的数据类型就称为“抽象数据类型”

继承

继承(Inheritance)是面向对象程序设计语言强大的功能,因为它允许程序代码的重复使用(Code Reusability,即代码可重复使用性),同时可以表达树形结构中父代与子代的遗传现象。继承类似现实生活中的遗传,允许我们定义一个新的类来继承现有的类,进而使用或修改继承而来的方法,并可在子类中加入新的数据成员与函数成员。

多态

多态(Polymorphism)也是面向对象设计的重要特性,可让软件在开发和维护时达到充分的延伸性。多态,按照英文单词字面意思就是一样东西同时具有多种不同的类型。在面向对象程序设计语音中,多态的定义简单来说就是利用类的继承结构先建立一个基类的对象。用户可通过对象的继承声明此对象向下继承为派生类对象,进而控制所有派生类的“同名异式”成员方法。简单地说,多态最直接的定义就是让具有继承关系的不同类对象可以调用相同名称的成员函数,并产生不同的反应结果。

1.3 面向对象中的关键术语

对象

对象(object)可以是抽象的概念或一个具体的东西,包括数据(Data)及其相应的操作或运算,或称为方法(Method),它具有状态(State)、行为(Behavior)与标识(Identity)

每一个对象均具有相应的属性及其属性值。例如,有一个学生的对象,“开学”是一条信息,可以传送给这个对象。而学生有学号、姓名、等属性,当前的属性值便是其状态,学生对象的操作或运算行为有注册、选修、转系、毕业等,学号是学生对象的唯一识别编号(对象表示,OID)

类(class)是具有相同结构及行为的组合,是许多对象共同特征的描述或对象的抽象化。例如乔峰和段誉都输入人这个类,他们都有出生年月日、血型、体重、身高等类的属性。类中的一个对象就称为该类的一个实例。

属性

属性(Attribute)用来描述对象的基本特征及其所属的性质。例如人的属性可能包括姓名、住址、年龄等。

方法

方法(Method)是面向对象数据库系统中对象的动作与行为,我们以人为例,不同的职业,其工作内容也会有所不同,学生的主要工作是学习,老师的主要工作是教书

2.Python的类与对象

2.1 定义类

类是由成员(Class Member)组成的,类在使用之前要先声明,语法如下:

class 类名称():
    # 定义初始化内容
    # 定义方法
  • class:创建类的关键字,必须配合冒号产生程序区块
  • 类名称: 用来指定所要闯进类的名称,类名称必须遵守标识符的命名规范
  • 定义方法是,与函数一样必须使用def语句

以下语句是最简单的定义类的方式,用来创建一个空类

class nothing:
    pass

上面的语句用来创建nothing类,使用pass语句表示什么都不做。

在定义类的过程中可以加入属性和方法,再以对象来存取其属性和方法。

2.2 类实例化

将类实例化就是创建对象,有了对象可可以进一步存取类中所定义的属性和方法。类实例化的语法如下:

对象 = 类名称(参数列表)
对象.属性
对象.方法()

参数列表可根据对象初始化进行选择,下面的语句可生成或创建两个对象boy1和boy2

boy1 = Person()
boy2 = Person()

上面的语句可视为创建Person类的实例,并将该对象赋值给变量boy1和boy2。

Python定义方法的第一个参数必须是自己,习惯上用self来表示,它代表创建类后实例化的对象。这是一个相当重要的特性。slef有点类似其他语言中的this,指向对象本身,在定义类的所有方法中都必须声明它。

class Hero:
    # 定义方法一:获取姓名和武功
    def setData(self, name, kungfu):
        self.name = name
        self.kungfu = kungfu
    # 定义方法二,输出姓名和功夫
    def getData(self):
        print(f"这位大侠叫{self.name},他会的武功是{self.kungfu}")

# 创建对象
hero1 = Hero() 
hero1.setData('乔峰','降龙十八掌')
hero1.getData()

hero2 = Hero()
hero2.setData('段誉','六脉神剑')
hero2.getData()

# 返回结果
这位大侠叫乔峰,他会的武功是降龙十八掌
这位大侠叫段誉,他会的武功是六脉神剑

2.3 对象初始化的init()方法

当创建对象时,init()会初始化对象,例如设置初始值或进行数据库连接等。这个方法的第一个参数时self,指向刚创建的对象本身。创建对象之后,良好的习惯是使用init()方法设置初始值。

class Rectangle:
    def __init__(self,length = 10 , width =5):
        self.lenght = length
        self.width = width
    def getArea(self):
        return self.lenght*self.width

R1 = Rectangle()
print('通过init()方法初始化设置的默认面积是:',R1.getArea())

R2 = Rectangle(125,6)
print('通过传入参数值计算的面积是:',R2.getArea())

# 返回
通过init()方法初始化设置的默认面积是: 50
通过传入参数值计算的面积是: 750

2.4 匿名对象

通常声明类后,会将类实例化为对象,并将对象赋值给变量,再通过这个变量来存取对象。在Python中有一项重要特性,就是每个东西都是对象,所以在编写程序时,也可以不把对象赋值给变量的情况下使用对象。这就是一种被称为匿名对象(Anonymous Object)的程序设计技巧

class Rectangle:
    def __init__(self,length = 10 , width =5):
        self.lenght = length
        self.width = width
    def getArea(self):
        return self.lenght*self.width
# 直接以匿名对象的方式存取对象
print('通过init()方法初始化设置的默认面积是:',Rectangle().getArea())
print('通过传入参数值计算的面积是:',Rectangle(125,6).getArea())
# 返回结果为
通过init()方法初始化设置的默认面积是: 50
通过传入参数值计算的面积是: 750

2.5 私有属性与方法

在前面的范例中,类外部的指令可以直接存取类内部的数据,这种做法具有风险性,容易造成内部数据被不当修改。如果某些类内部的重要数据不希望被任何人擅自修改,目前这种编写程序的方式就存在问题。

为了达到保护类内部数据的目的,我们可以将这些重要数据设置为私有属性,如此一来,就可以限定该数据只能由类内部的指令或语句来存取。当类外部需要存取这些私有的数据时,就不能直接从类外部进行存取,必须通过该类所提供的公有方法。这种做法较为安全,可以有效保护一些不想被修改的重要数据。

把属性指定为私有的,只要在该属性名称前面加上两个下划线”“即可,就代表该属性为私有属性。不过要特别注意,在名称后面不能有下划线,例如”__age”是私有属性,但是__age就不是私有属性。下面的实例为私有属性的应用例子,其中__rate是私有属性,当类外部想要存取__rate私有属性数据时,并不能直接从类外部进行存取,必须通过该类所提供的getRate()共有方法。

class Discount:
    def __init__(self , r = 0.9):
        self.__rate = r
    def getRate(self):
        return self.__rate
    def howMuch(self):
        return money*self.__rate

money = 10000
obj1 = Discount(0.7)
print('此件商品的原有价格为',money,'元')
print('此件商品的折扣为',obj1.getRate())
print('此件商品的折后价格为',obj1.howMuch(),'元')
# 返回
此件商品的原有价格为 10000 元
此件商品的折扣为 0.7
此件商品的折后价格为 7000.0 元

从上面的执行结果可以看到,由于__rate是一个私有属性,必须通过类中定义的getRate()方法才能获取,如果我们尝试直接存取私有属性,看看结果如何:

class Discount:
    def __init__(self , r = 0.9):
        self.__rate = r
    def getRate(self):
        return self.__rate
    def howMuch(self):
        return money*self.__rate

money = 10000
obj1 = Discount(0.7)
print('此件商品的原有价格为',money,'元')
print('此件商品的折扣为',obj1.__rate)
print('此件商品的折后价格为',obj1.howMuch(),'元')
# 返回结果为
   print('此件商品的折扣为',obj1.__rate)
AttributeError: 'Discount' object has no attribute '__rate'

除了属性成员可以设置为私有之外,类的方法成员同样可以设为私有,同样是在方法名称前面加上两个下划线即可。一旦被声明为私有方法后,该方法只能被类内部的语句调用,在类外部就不能直接调用该私有方法了。无论是私有属性还是私有方法,其目的就是帮助程序设计人员为需要保护的属性和方法上加上一道保护措施,以达到信息隐藏的目的。

发表评论

邮箱地址不会被公开。 必填项已用*标注