【Python核心】面向对象
从C++或者JAVA 语言入手学编程,好不容易搞懂了最基本的数据类型、赋值判断和循环,却又迎面撞上了OOP(object oriented programming)的大墙,一头扎进公有私有保护、多重继承、多态派生、纯函数、抽象类、友元函数等一堆专有名词的汪洋大海中找不到彼岸,于是就放弃了进阶之路
相比之下,Python是一门相对友好的语言,它在创立之初就鼓励命令交互式的轻量级编程
传统的命令式语言有无数重复性代码,虽然函数的诞生减缓了许多重复性,但随着计算机的发展,只有函数依然不够,需要把更加抽象的概念引入计算机才能缓解(而不是解决)这个问题,于是OOP应运而生
Python一步步攻城掠地飞速发展,从最基础的脚本程序,到后来可以编写系统程序、大型工程、数据科学运算、人工智能,早已脱离了当初的设计,因此一些其他语言的优秀设计之处依然需要引入
一、对象,你找到了吗
先来学习,面向对象编程中最基本的概念
1.1 生活类比
为了方便理解其中的抽象概念,打个比方感受一下
生物课上,学过"界门纲目科属种"的概念,核心思想是科学家们根据各种动植物、微生物的相似之处,将其分化为不同的类型方便研究。生活中也是如此,习惯对身边的事物进行分类:
- 猫和狗都是动物
- 直线和圆都是平面几何的图形
- 《哈利波特》和《冰与火之歌》都是小说
自然,同一类事物便会有着相似的特性:
- 动物会动
- 平面图形有面积和周长
- 小说有相应的作者和大致情节等各种元素
1.2 几个概念
那回到Python上又对应哪些内容呢?这里,先来看一段最基本的Python面向对象的应用代码
class Document():def __init__(self, title, author, context):print('init function called')self.title = titleself.author = authorself.__context = context # __开头的属性是私有属性def get_context_length(self):return len(self.__context)def intercept_context(self, length):self.__context = self.__context[:length]harry_potter_book = Document('Harry Potter', 'J. K. Rowling', '... Forever Do not believe any thing is capable of thinking independently ...')print(harry_potter_book.title)
print(harry_potter_book.author)
print(harry_potter_book.get_context_length())harry_potter_book.intercept_context(10)print(harry_potter_book.get_context_length())print(harry_potter_book.__context)########## 输出 ##########init function called
Harry Potter
J. K. Rowling
77
10---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-5-b4d048d75003> in <module>()22 print(harry_potter_book.get_context_length())23
---> 24 print(harry_potter_book.__context)AttributeError: 'Document' object has no attribute '__context'
参照着这段代码,先简单解释几个概念
- 类
一群有着相似性的事物的集合,这里对应Python的class
- 对象
集合中的一个事物,这里对应由class
生成的某一个object
,比如代码中的harry_potter_book
- 属性
对象的某个静态特征,比如上述代码中的title
、author
和__context
- 函数
对象的某个动态能力,比如上述代码中的intercept_context()
函数
1.3 类的严谨定义
当然,这样的说法既不严谨,也不充分,但如果对面向对象编程完全不了解,它们可以让你迅速有一个直观的了解
还是通过刚刚那段代码,再给类下一个更为严谨的定义
1.3.1 什么是类
类,一群有着相同属性和函数的对象的集合
虽然有循环论证之嫌,但是反复强调还是希望能对面向对象的最基础的思想,有更真实的了解。清楚记住这一点后,接下来具体解读刚刚这段代码
class Document():def __init__(self, title, author, context):print('init function called')self.title = titleself.author = authorself.__context = context # __开头的属性是私有属性def get_context_length(self):return len(self.__context)def intercept_context(self, length):self.__context = self.__context[:length]harry_potter_book = Document('Harry Potter', 'J. K. Rowling', '... Forever Do not believe any thing is capable of thinking independently ...')print(harry_potter_book.title)
print(harry_potter_book.author)
print(harry_potter_book.get_context_length())harry_potter_book.intercept_context(10)print(harry_potter_book.get_context_length())print(harry_potter_book.__context)########## 输出 ##########init function called
Harry Potter
J. K. Rowling
77
10---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-5-b4d048d75003> in <module>()22 print(harry_potter_book.get_context_length())23
---> 24 print(harry_potter_book.__context)AttributeError: 'Document' object has no attribute '__context'
可以看到,class Document定义了Document类,再往下能看到它有三个函数,这三个函数即为 Document类的三个函数
1.3.2 init构造函数
其中,init表示构造函数,意即一个对象生成时会被自动调用的函数
可以看到harry_potter_book = Document(...)
这一行代码被执行的时候,init function called
字符串会被打印出来
1.3.3 普通函数
get_context_length()
和intercept_context()
则为类的普通函数,调用它们来对对象的属性做一些事情
1.3.4 类的属性
class Document有三个属性,title
、author
和__context
分别表示标题、作者和内容,通过构造函数传入
这里代码很直观,可以看到intercept_context
能修改对象harry_potter_book
的__context
属性
- 私有属性
这里唯一需要强调的一点是,如果一个属性以__(注意,两个 _)开头,默认这个属性是私有属性
私有属性,是指不希望在类的函数之外的地方被访问和修改的属性。所以,可以看到title
和author
能够很自由地被打印出来,但是print(harry_potter_book.__context)
就会报错
二、更复杂的一些问题
掌握了最基础的概念,其实已经能做很多很多的事情了。不过,在工程实践中,随着复杂度继续提升,可能会遇到一些问题:
- 如何在一个类中定义一些常量,每个对象都可以方便访问这些常量而不用重新构造?
- 如果一个函数不涉及到访问修改这个类的属性,而放到类外面有点不恰当,怎么做才能更优雅呢?
- 既然类是一群相似的对象的集合,那么可不可以是一群相似的类的集合呢?
前两个问题很好解决,不过,它们涉及到一些常用的代码规范,看下面一段代码示例
class Document():WELCOME_STR = 'Welcome! The context for this book is {}.'def __init__(self, title, author, context):print('init function called')self.title = titleself.author = authorself.__context = context# 类函数@classmethoddef create_empty_book(cls, title, author):return cls(title=title, author=author, context='nothing')# 成员函数def get_context_length(self):return len(self.__context)# 静态函数@staticmethoddef get_welcome(context):return Document.WELCOME_STR.format(context)empty_book = Document.create_empty_book('What Every Man Thinks About Apart from Sex', 'Professor Sheridan Simove')print(empty_book.get_context_length())
print(empty_book.get_welcome('indeed nothing'))########## 输出 ##########init function called
7
Welcome! The context for this book is indeed nothing.
2.1 常量的定义
第一个问题,在Python的类里,只需要和函数并列地声明并赋值就可以实现这一点,例如这段代码中的WELCOME_STR
一种很常规的做法,是用全大写来表示常量,因此可以在类中使用self.WELCOME_STR
,或者在类外使用Entity.WELCOME_STR
来表达这个字符串
2.2 静态函数
而针对第二个问题,提出了类函数、成员函数和静态函数三个概念
它们其实很好理解,前两者产生的影响是动态的,能够访问或者修改对象的属性,而静态函数则与类没有什么关联,最明显的特征便是,静态函数的第一个参数没有任何特殊性
具体来看这几种函数。一般而言,静态函数可以用来做一些简单独立的任务,既方便测试,也能优化代码结构
静态函数还可以通过在函数前一行加上@staticmethod
来表示,代码中也有相应的示例
2.3 类函数
而类函数的第一个参数一般为cls
,表示必须传一个类进来
类函数最常用的功能是实现不同的init
构造函数,比如上文代码中使用create_empty_book
类函数来创造新的书籍对象,其context
一定为nothing
这样的代码,比直接构造要清晰一些。类似的,类函数需要装饰器@classmethod
来声明
2.4 成员函数
成员函数则是最正常的类的函数,它不需要任何装饰器声明,第一个参数self代表当前对象的引用,可以通过此函数来实现想要的查询/修改类的属性等功能
三、类的继承
3.1 多个类的集合
接下来,看一下上面所说的第三个问题,既然类是一群相似的对象的集合,那么可不可以是一群相似的类的集合呢?
答案是,当然可以
只要抽象得好,类可以描述成任何事物的集合。当然要小心、严谨地去定义它
3.2 父类和子类
类的继承,顾名思义指的是一个类既拥有另一个类的特征,也拥有不同于另一个类的独特特征
在这里的第一个类叫做子类,另一个叫做父类,特征其实就是类的属性和函数
class Entity():def __init__(self, object_type):print('parent class init called')self.object_type = object_typedef get_context_length(self):raise Exception('get_context_length not implemented')def print_title(self):print(self.title)class Document(Entity):def __init__(self, title, author, context):print('Document class init called')Entity.__init__(self, 'document')self.title = titleself.author = authorself.__context = contextdef get_context_length(self):return len(self.__context)class Video(Entity):def __init__(self, title, author, video_length):print('Video class init called')Entity.__init__(self, 'video')self.title = titleself.author = authorself.__video_length = video_lengthdef get_context_length(self):return self.__video_lengthharry_potter_book = Document('Harry Potter(Book)', 'J. K. Rowling', '... Forever Do not believe any thing is capable of thinking independently ...')
harry_potter_movie = Video('Harry Potter(Movie)', 'J. K. Rowling', 120)print(harry_potter_book.object_type)
print(harry_potter_movie.object_type)harry_potter_book.print_title()
harry_potter_movie.print_title()print(harry_potter_book.get_context_length())
print(harry_potter_movie.get_context_length())########## 输出 ##########Document class init called
parent class init called
Video class init called
parent class init called
document
video
Harry Potter(Book)
Harry Potter(Movie)
77
120
同样结合代码来学习这些概念。在这段代码中,Document和Video有相似的地方,都有相应的标题、作者和内容等属性。可以从中抽象出一个叫做Entity的类,来作为它俩的父类
3.3 构造函数
首先需要注意的是构造函数
每个类都有构造函数,继承类在生成对象的时候是不会自动调用父类的构造函数的,因此必须在init()函数中显式调用父类的构造函数,执行顺序是子类的构造函数->父类的构造函数
3.4 函数重写
其次需要注意父类get_context_length()函数
如果使用Entity直接生成对象,调用get_context_length()
函数,就会raise error
中断程序的执行。使用函数重写的方式,可以使子类必须重新写一遍get_context_length()
函数来覆盖掉原有函数
3.5 父类函数继承
最后需要注意到print_title()
函数
这个函数定义在父类中,但是子类的对象可以毫无阻力地使用它来打印title,这也就体现了继承的优势:减少重复的代码,降低系统的熵值(即复杂度)
3.6 抽象类
最后,再扩展一下抽象函数和抽象类,同样会用一段代码来辅助讲解
from abc import ABCMeta, abstractmethodclass Entity(metaclass=ABCMeta):@abstractmethoddef get_title(self):pass@abstractmethoddef set_title(self, title):passclass Document(Entity):def get_title(self):return self.titledef set_title(self, title):self.title = titledocument = Document()
document.set_title('Harry Potter')
print(document.get_title())entity = Entity()########## 输出 ##########Harry Potter---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-7-266b2aa47bad> in <module>()21 print(document.get_title())22
---> 23 entity = Entity()24 entity.set_title('Test')TypeError: Can't instantiate abstract class Entity with abstract methods get_title, set_title
可以发现,Entity本身是没有什么用,只需拿来定义Document和Video的一些基本元素就够了
不过,万一不小心生成Entity的对象该怎么办呢?为了防止这样的问题必须要介绍一下抽象类
抽象类是一种特殊的类,它生下来就是作为父类存在的,一旦对象化就会报错。同样,抽象函数定义在抽象类之中,子类必须重写该函数才能使用。相应的抽象函数则是使用装饰器@abstractmethod
来表示
可以看到,代码中entity = Entity()
直接报错,只有通过Document继承Entity才能正常使用
抽象类就是这么一种存在,是一种自上而下的设计风范,只需要用少量的代码描述清楚要做的事情,定义好接口,然后就可以交给不同开发人员去开发和对接
【Python核心】面向对象相关推荐
- 16.1、python初识面向对象(1)
初识面向对象 楔子 你现在是一家游戏公司的开发人员,现在需要你开发一款叫做<人狗大战>的游戏,你就思考呀,人狗作战,那至少需要2个角色,一个是人, 一个是狗,且人和狗都有不同的技能,比如人 ...
- Python之面向对象类和对象
Python之面向对象类和对象 定义一个类:class 定义类的语法: class Test(object):"""类里定义一类事物共同的技能.可以是变量,也可是函数.& ...
- 拒绝从入门到放弃_《Python 核心编程 (第二版)》必读目录
目录 目录 关于这本书 必看知识点 最后 关于这本书 <Python 核心编程 (第二版)>是一本 Python 编程的入门书,分为 Python 核心(其实并不核心,应该叫基础) 和 高 ...
- python核心编程第三版_Python之父:自学python,这3本书能节约你一大半时间编程...
今天给大家推荐三本书,有两本是属于一个系列,即<Python核心编程>第二版和第三版,一本讲基础和一本讲进阶,非常适合Python的初学者和有一定基础的学习者.还有一本书适合所有想学Pyt ...
- 对《Python核心编程》中“第一个Python程序”的改进
概述: 本程序主要是模仿<Python核心编程>中3.6节--第一个Python程序,并在其基础上做了一些小的改进,而改进的要求则是来源于第三章的课后练习题. 本篇博客的一个核心问题就是在 ...
- python3 socketserver_《Python核心编程(第3版)》——2.5 *SocketServer模块
本节书摘来自异步社区<Python核心编程(第3版)>一书中的第2章,第2.5节,作者[美] Wesley Chun(卫斯理 春),孙波翔 李斌 李晗 译,更多章节内容可以访问云栖社区&q ...
- python人工智能_人工智能福利丨Python核心语法实战
Python已正式跻身成熟语言行列,成为整个互联网的基础性语言之一,并以肉眼可见的速度,在全球攻城略地: --牢牢占据TIOBE世界编程语言排行榜第四名,且保持上升趋势 --国家级人工智能四大平台确立 ...
- python基础——面向对象的程序设计
python基础--面向对象的程序设计 1 什么是面向对象的程序设计 面向过程的程序设计的核心是过程,过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西. 优 ...
- 《Python核心编程(第3版)》——1.3 正则表达式和Python语言
本节书摘来自异步社区<Python核心编程(第3版)>一书中的第1章,第1.3节,作者[美] Wesley Chun(卫斯理 春),孙波翔 李斌 李晗 译,更多章节内容可以访问云栖社区&q ...
- python核心编程第三版_《Python核心编程(第3版)》
<Python核心编程(第3版)>是经典畅销图书<Python核心编程(第二版)>的全新升级版本,本书适合具有一定经验的Python开发人员阅读,总共分为3部分.第1部分为讲解 ...
最新文章
- Hitcon 2016 Pwn赛题学习
- 人工智能伦理如何设定,从种群层面看人类的知识积累和进化
- Xtract 实现 VMware Vsphere 迁主机到 Nutanix cluster
- 论文浅尝 - ACL2020 | 利用常识知识图对会话流进行显式建模
- 谷歌要构建自己的区块链技术
- lucene创建索引的几种方式(一)
- html生成器_这些文案生成器,你知道几个?
- 使用 Blueprint 要注意 render_template 函数
- 全民一起玩python实战篇百度云_【全民一起玩python】下载 - 面包树
- 【利用FLASH制作交互式课件】
- 科研小白如何有效下载英文文献和英文书籍?
- 计算机电子表格操作步骤,Excel电子表格操作基本步骤.doc
- ubuntu更新时Not enough free disk space
- 荐书 | 22本颠覆我们认知的思维方式(上)
- 项目中有时候为什么加载不出来图片
- Codeforces #467 (Div. 2) B. Vile Grasshoppers 蚂蚱的题目
- 我为何一直强调外包公司别去
- 符合Chrome58的证书制作
- Android布局文件中的xmlns:tools作用以及用法
- Markdown 常用语法