谈一谈基于python的面向对象编程基础

活在当下的程序员应该都听过“面向对象编程”一词,也经常有人问能不能用一句话解释下什么是“面向对象编程”,我们先来看看比较正式的说法。

把一组数据结构和处理它们的方法组成对象(object),把相同行为的对象归纳为类(class),通过类的封装(encapsulation)隐藏内部细节,通过继承(inheritance)实现类的特化(specialization)和泛化(generalization),通过多态(polymorphism)实现基于对象类型的动态分派。

这样一说是不是更不明白了。所以我们还是看看更通俗易懂的说法,下面这段内容来自于知乎。

说明: 以上的内容来自于网络,不代表作者本人的观点和看法,与作者本人立场无关,相关责任不由作者承担。

之前我们说过“程序是指令的集合”,我们在程序中书写的语句在执行时会变成一条或多条指令然后由CPU去执行。当然为了简化程序的设计,我们引入了函数的概念,把相对独立且经常重复使用的代码放置到函数中,在需要使用这些功能的时候只要调用函数即可;如果一个函数的功能过于复杂和臃肿,我们又可以进一步将函数继续切分为子函数来降低系统的复杂性。但是说了这么多,不知道大家是否发现,所谓编程就是程序员按照计算机的工作方式控制计算机完成各种任务。但是,计算机的工作方式与正常人类的思维模式是不同的,如果编程就必须得抛弃人类正常的思维方式去迎合计算机,编程的乐趣就少了很多,“每个人都应该学习编程”这样的豪言壮语就只能说说而已。当然,这些还不是最重要的,最重要的是当我们需要开发一个复杂的系统时,代码的复杂性会让开发和维护工作都变得举步维艰,所以在上世纪60年代末期,“软件危机”、“软件工程”等一系列的概念开始在行业中出现。

当然,程序员圈子内的人都知道,现实中并没有解决上面所说的这些问题的“银弹”,真正让软件开发者看到希望的是上世纪70年代诞生的Smalltalk编程语言中引入的面向对象的编程思想(面向对象编程的雏形可以追溯到更早期的Simula语言)。按照这种编程理念,程序中的数据和操作数据的函数是一个逻辑上的整体,我们称之为“对象”,而我们解决问题的方式就是创建出需要的对象并向对象发出各种各样的消息,多个对象的协同工作最终可以让我们构造出复杂的系统来解决现实中的问题。

说明: 当然面向对象也不是解决软件开发中所有问题的最后的“银弹”,所以今天的高级程序设计语言几乎都提供了对多种编程范式的支持,Python也不例外。

类和对象

简单的说,类是对象的蓝图和模板,而对象是类的实例。这个解释虽然有点像用概念在解释概念,但是从这句话我们至少可以看出,类是抽象的概念,而对象是具体的东西。在面向对象编程的世界中,一切皆为对象,对象都有属性和行为,每个对象都是独一无二的,而且对象一定属于某个类(型)。当我们把一大堆拥有共同特征的对象的静态特征(属性)和动态特征(行为)都抽取出来后,就可以定义出一个叫做“类”的东西。

定义类

在Python中可以使用class关键字定义类,然后在类中通过之前学习过的函数来定义方法,这样就可以将对象的动态特征描述出来,代码如下所示。

class Student(object):

 # __init__是一个特殊方法用于在创建对象时进行初始化操作
 # 通过这个方法我们可以为学生对象绑定name和age两个属性
 def __init__(self, name, age):
  self.name = name
  self.age = age

 def study(self, course_name):
  print('%s正在学习%s.' % (self.name, course_name))

 # PEP 8要求标识符的名字用全小写多个单词用下划线连接
 # 但是很多程序员和公司更倾向于使用驼峰命名法(驼峰标识)
 def watch_av(self):
  if self.age < 18:
   print('%s只能观看《熊出没》.' % self.name)
  else:
   print('%s正在观看岛国爱情动作片.' % self.name)

说明: 写在类中的函数,我们通常称之为(对象的)方法,这些方法就是对象可以接收的消息。

创建和使用对象

当我们定义好一个类之后,可以通过下面的方式来创建对象并给对象发消息。

def main():
 # 创建学生对象并指定姓名和年龄
 stu1 = Student('骆昊', 38)
 # 给对象发study消息
 stu1.study('Python程序设计')
 # 给对象发watch_av消息
 stu1.watch_av()
 stu2 = Student('王大锤', 15)
 stu2.study('思想品德')
 stu2.watch_av()

if __name__ == '__main__':
 main()

访问可见性问题

对于上面的代码,有C++、Java、C#等编程经验的程序员可能会问,我们给Student对象绑定的name和age属性到底具有怎样的访问权限(也称为可见性)。因为在很多面向对象编程语言中,我们通常会将对象的属性设置为私有的(private)或受保护的(protected),简单的说就是不允许外界访问,而对象的方法通常都是公开的(public),因为公开的方法就是对象能够接受的消息。在Python中,属性和方法的访问权限只有两种,也就是公开的和私有的,如果希望属性是私有的,在给属性命名时可以用两个下划线作为开头,下面的代码可以验证这一点。

class Test:

 def __init__(self, foo):
  self.__foo = foo

 def __bar(self):
  print(self.__foo)
  print('__bar')

def main():
 test = Test('hello')
 # AttributeError: 'Test' object has no attribute '__bar'
 test.__bar()
 # AttributeError: 'Test' object has no attribute '__foo'
 print(test.__foo)

if __name__ == "__main__":
 main()

但是,Python并没有从语法上严格保证私有属性或方法的私密性,它只是给私有的属性和方法换了一个名字来“妨碍”对它们的访问,事实上如果你知道更换名字的规则仍然可以访问到它们,下面的代码就可以验证这一点。之所以这样设定,可以用这样一句名言加以解释,就是“We are all consenting adults here”。因为绝大多数程序员都认为开放比封闭要好,而且程序员要自己为自己的行为负责。

class Test:

 def __init__(self, foo):
  self.__foo = foo

 def __bar(self):
  print(self.__foo)
  print('__bar')

def main():
 test = Test('hello')
 test._Test__bar()
 print(test._Test__foo)

if __name__ == "__main__":
 main()

在实际开发中,我们并不建议将属性设置为私有的,因为这会导致子类无法访问(后面会讲到)。所以大多数Python程序员会遵循一种命名惯例就是让属性名以单下划线开头来表示属性是受保护的,本类之外的代码在访问这样的属性时应该要保持慎重。这种做法并不是语法上的规则,单下划线开头的属性和方法外界仍然是可以访问的,所以更多的时候它是一种暗示或隐喻

面向对象的支柱

面向对象有三大支柱:封装、继承和多态。后面两个概念在下一个章节中进行详细的说明,这里我们先说一下什么是封装。我自己对封装的理解是“隐藏一切可以隐藏的实现细节,只向外界暴露(提供)简单的编程接口”。我们在类中定义的方法其实就是把数据和对数据的操作封装起来了,在我们创建了对象之后,只需要给对象发送一个消息(调用方法)就可以执行方法中的代码,也就是说我们只需要知道方法的名字和传入的参数(方法的外部视图),而不需要知道方法内部的实现细节(方法的内部视图)。

练习

练习1:定义一个类描述数字时钟

class Clock(object):
 """数字时钟"""

 def __init__(self, hour=0, minute=0, second=0):
  """初始化方法

  :param hour: 时
  :param minute: 分
  :param second: 秒
  """
  self._hour = hour
  self._minute = minute
  self._second = second

 def run(self):
  """走字"""
  self._second += 1
  if self._second == 60:
   self._second = 0
   self._minute += 1
   if self._minute == 60:
    self._minute = 0
    self._hour += 1
    if self._hour == 24:
     self._hour = 0

 def show(self):
  """显示时间"""
  return '%02d:%02d:%02d' % \
    (self._hour, self._minute, self._second)

def main():
 clock = Clock(23, 59, 58)
 while True:
  print(clock.show())
  sleep(1)
  clock.run()

if __name__ == '__main__':
 main()

练习2:定义一个类描述平面上的点并提供移动点和计算到另一个点距离的方法。

from math import sqrt

class Point(object):

 def __init__(self, x=0, y=0):
  """初始化方法

  :param x: 横坐标
  :param y: 纵坐标
  """
  self.x = x
  self.y = y

 def move_to(self, x, y):
  """移动到指定位置

  :param x: 新的横坐标
  "param y: 新的纵坐标
  """
  self.x = x
  self.y = y

 def move_by(self, dx, dy):
  """移动指定的增量

  :param dx: 横坐标的增量
  "param dy: 纵坐标的增量
  """
  self.x += dx
  self.y += dy

 def distance_to(self, other):
  """计算与另一个点的距离

  :param other: 另一个点
  """
  dx = self.x - other.x
  dy = self.y - other.y
  return sqrt(dx ** 2 + dy ** 2)

 def __str__(self):
  return '(%s, %s)' % (str(self.x), str(self.y))

def main():
 p1 = Point(3, 5)
 p2 = Point()
 print(p1)
 print(p2)
 p2.move_by(-1, 2)
 print(p2)
 print(p1.distance_to(p2))

if __name__ == '__main__':
 main()

说明: 本章中的插图来自于Grady Booch等著作的《面向对象分析与设计》一书,该书是讲解面向对象编程的经典著作,有兴趣的读者可以购买和阅读这本书来了解更多的面向对象的相关知识。

(0)

相关推荐

  • Python3.5面向对象编程图文与实例详解

    本文实例讲述了Python3.5面向对象编程.分享给大家供大家参考,具体如下: 1.面向过程与面向对象的比较 (1)面向过程编程(procedural programming) 面向过程编程又被称为:top-down languages,程序从上到下 一步步执行,从头到尾的解决问题. 基本设计思路为:程序一开始是解决一个大问题,然后把大问题分解成多个小问题或子过程,这些小问题执行的时候再继续分解, 直到小问题足够简单到可以在一个小范围内解决. 缺点:若程序要进行修改,则修改的部分依赖的各个部分也

  • Python面向对象总结及类与正则表达式详解

    Python3 面向对象 -------------------------------------------------------------------------------- 一丶面向对象技术简介 •类(Class): 用来描述具有相同的属性和方法的对象的集合.它定义了该集合中每个对象所共有的属性和方法.对象是类的实例. •方法:类中定义的函数. •类变量:类变量在整个实例化的对象中是公用的.类变量定义在类中且在函数体之外.类变量通常不作为实例变量使用. •数据成员:类变量或者实例变

  • python面向对象实现名片管理系统文件版

    本文实例为大家分享了python实现名片管理系统源代码,供大家参考,具体内容如下 import os def print_menu(): print("*"*50) print(" 名片管理系统") print(" 1.添加一个新名片") print(" 2.删除一个名片信息") print(" 3.修改一个名片信息") print(" 4.查找一个名片信息") print("

  • python面向对象法实现图书管理系统

    本文实例为大家分享了python实现图书管理系统的具体代码,供大家参考,具体内容如下 需求: 图书管理系统 1.查询图书 2.增加图书 3.借阅图书 4.归还图书 5.退出系统 书:书名,作者,状态,位置 管理系统: 实现如下: class Book(object): def __init__(self, name, author, status, bookindex): self.name = name self.author = author self.status = status sel

  • Python面向对象进阶学习

    在前面的章节我们已经了解了面向对象的入门知识,知道了如何定义类,如何创建对象以及如何给对象发消息.为了能够更好的使用面向对象编程思想进行程序开发,我们还需要对Python中的面向对象编程进行更为深入的了解. @property装饰器 之前我们讨论过Python中属性和方法访问权限的问题,虽然我们不建议将属性设置为私有的,但是如果直接将属性暴露给外界也是有问题的,比如我们没有办法检查赋给属性的值是否有效.我们之前的建议是将属性命名以单下划线开头,通过这种方式来暗示属性是受保护的,不建议外界直接访问

  • Python3.5面向对象程序设计之类的继承和多态详解

    本文实例讲述了Python3.5面向对象程序设计之类的继承和多态.分享给大家供大家参考,具体如下: 1.继承的定义 继承是指:可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展. (1)通过继承创建的新类称为"子类"或"派生类". (2)被继承的类称为"基类"."父类"或"超类". 继承的过程,就是从一般到特殊的过程.要实现继承,可以通过"继承"(Inherit

  • Python3.5面向对象与继承图文实例详解

    本文实例讲述了Python3.5面向对象与继承.分享给大家供大家参考,具体如下: 1.编程的方式 2.面向对象的基本概念 3.类的基本概念 4.类的定义与调用--简单代码举例 注:建议类名的开头字母用大写,在Python中,类内的函数称作方法,类外的函数还是称作函数. #!/usr/bin/env python # -*- coding:utf-8 -*- # Author:ZhengzhengLiu #类 class Person: i = 10 #属性(变量) def eat(self):

  • 谈一谈基于python的面向对象编程基础

    活在当下的程序员应该都听过"面向对象编程"一词,也经常有人问能不能用一句话解释下什么是"面向对象编程",我们先来看看比较正式的说法. 把一组数据结构和处理它们的方法组成对象(object),把相同行为的对象归纳为类(class),通过类的封装(encapsulation)隐藏内部细节,通过继承(inheritance)实现类的特化(specialization)和泛化(generalization),通过多态(polymorphism)实现基于对象类型的动态分派.

  • Python面向对象编程基础解析(一)

    1.什么是面向对象 面向对象(oop)是一种抽象的方法来理解这个世界,世间万物都可以抽象成一个对象,一切事物都是由对象构成的.应用在编程中,是一种开发程序的方法,它将对象作为程序的基本单元. 2.面向对象与面向过程的区别 我们之前已经介绍过面向过程了,面向过程的核心在'过程'二字,过程就是解决问题的步骤,面向过程的方法设计程序就像是在设计一条流水线,是一种机械式的思维方式 优点:复杂的问题简单化,流程化 缺点:扩展性差 主要应用场景有:Linux内核,git,以及http服务 面向对象的程序设计

  • 基于Python实现面向对象版学生管理系统

    目录 一.目标 二.系统需求 三.准备程序文件 1. 分析 2. 创建程序文件 四.书写程序 1. student.py 2. 管理系统需求 3. main.py 4. 定义系统功能函数 4.1 添加学生 4.2 删除学生 4.3 修改学生信息 4.5 查询学生信息 4.6 显示所有学生信息 4.7 保存学生信息 4.8 加载学生信息 五.源代码 main.py student.py managerSystem.py 六.总结 一.目标 了解面向对象开发过程中类内部功能的分析方法 了解常用系统功

  • Python面向对象编程基础解析(二)

    Python最近挺火呀,比鹿晗薛之谦还要火,当然是在程序员之间.下面我们看看有关Python的相关内容. 上一篇文章我们已经介绍了部分Python面向对象编程基础的知识,大家可以参阅:Python面向对象编程基础解析(一),接下来,我们看看另一篇. 封装 1.为什么要封装? 封装就是要把数据属性和方法的具体实现细节隐藏起来,只提供一个接口.封装可以不用关心对象是如何构建的,其实在面向对象中,封装其实是最考验水平的 2.封装包括数据的封装和函数的封装,数据的封装是为了保护隐私,函数的封装是为了隔离

  • Python面向对象编程基础实例分析

    本文实例讲述了Python面向对象编程基础.分享给大家供大家参考,具体如下: 1.类的定义 Python中类的定义与对象的初始化如下,python中所有类的父类是object,需要继承. 由于Python是动态语言,因此可以直接为对象添加属性并赋值而不必在类定义中声明 class Person(object): # 定义一个Person类 pass p = Person() # 初始化一个Person对象 p.name="xiaoming" # 对象属性赋值 Python的类初始化方法

  • PowerShell面向对象编程基础知识总结

    本文介绍PowerShell面向对象编程的基础知识,我们知道PowerShell里面的所有变量和输出都是对象,所以有必要在进行PowerShell编程时了解一下面向对象编程的基础知识. 面向对象编程的引入主要是为了解决软件复杂化带来的维护等问题,早在20世纪60年代,面向对象就已经出现了.虽然C语言并不支持面向对象的特性,但是使用C语言进行开发的程序人员已经将面向对象的核心思想应用到其中,因此我们更应该理解的是面向对象的思想,而不需要纠缠于语言本身. PowerShell是基于对象的脚本语言,因

  • 深入讲解Python中面向对象编程的相关知识

    Python从第一天开始就是面向对象的语言.正因为如此,创建和使用类和对象是非常地容易.本章将帮助您在使用Python面向对象编程的技术方面所有提高. 如果没有任何以往面向对象(OO)的编程的经验,那么可能要了解一些基本的入门课程就可以了,或者至少某种形式的教程,让你有了解基本概念. 但是,这里会比较少地介绍面向对象编程(OOP): OOP术语概述 类: 用户定义的原型对象,它定义了一套描述类的任何对象的属性.属性是数据成员(类变量和实例变量)和方法,通过点符号访问. 类变量:这是一个类的所有实

  • JavaScript的面向对象编程基础

    重新认识面向对象 为了说明 JavaScript 是一门彻底的面向对象的语言,首先有必要从面向对象的概念着手 , 探讨一下面向对象中的几个概念: 一切事物皆对象 对象具有封装和继承特性 对象与对象之间使用消息通信,各自存在信息隐藏 以这三点做为依据,C++ 是半面向对象半面向过程语言,因为,虽然他实现了类的封装.继承和多态,但存在非对象性质的全局函数和变量.Java.C# 是完全的面向对象语言,它们通过类的形式组织函数和变量,使之不能脱离对象存在.但这里函数本身是一个过程,只是依附在某个类上.

  • JS面向对象编程基础篇(二) 封装操作实例详解

    本文实例讲述了JS面向对象编程封装操作.分享给大家供大家参考,具体如下: Javascript是一种基于对象(object-based)的语言,你遇到的所有东西几乎都是对象.但是,它又不是一种真正的面向对象编程(OOP)语言,因为它的语法中没有class(类). 那么,如果我们要把"属性"(property)和"方法"(method),封装成一个对象,甚至要从原型对象生成一个实例对象,我们应该怎么做呢? 封装 一. 生成实例对象的原始模式 假定我们把猫看成一个对象,

  • javascript 面向对象编程基础 多态

    Javascript已经可以模拟出面向对象的封装和继承特性,但是不幸的是Javascript对多态特性的支持非常弱!其它面向对象语言的多态一般都由方法重载和虚方法来实现多态,Javascript也通过这两种途径来实现! 重载:由于Javascript是弱类型的语言,而且又支持可变参数,当我们定义重载方法的时候,解释器无法通过参数类型和参数个数来区分不同的重载方法,因此方法重载是不被支持的!当先后定义了同名的方法的时候,后定义的方法会覆盖先定义的方法! 既然解释器无法分辨重载方法,那就手动区分不同

随机推荐