Python基础知识总结

1. Python基础知识

1.1  Python历史

1.1.1 Python起源

Python的作者,Guido von Rossum,荷兰人。1982年,Guido从阿姆斯特丹大学获得了数学和计算机硕士学位。然而,尽管他算得上是一位数学家,但他更加享受计算机带来的乐趣。用他的话说,尽管拥有数学和计算机双料资质,他总趋向于做计算机相关的工作,并热衷于做任何和编程相关的活儿。

在那个时候,Guido接触并使用过诸如Pascal、C、Fortran等语言。这些语言的基本设计原则是让机器能更快运行。在80年代,虽然IBM和苹果已经掀起了个人电脑浪潮,但这些个人电脑的配置很低。比如早期的Macintosh,只有8MHz的CPU主频和128KB的RAM,一个大的数组就能占满内存。所有的编译器的核心是做优化,以便让程序能够运行。为了增进效率,语言也迫使程序员像计算机一样思考,以便能写出更符合机器口味的程序。在那个时代,程序员恨不得用手榨取计算机每一寸的能力。有人甚至认为C语言的指针是在浪费内存。至于动态类型,内存自动管理,面向对象…… 别想了,那会让你的电脑陷入瘫痪。

这种编程方式让Guido感到苦恼。Guido知道如何用C语言写出一个功能,但整个编写过程需要耗费大量的时间,即使他已经准确的知道了如何实现。他的另一个选择是shell。Bourne Shell作为UNIX系统的解释器已经长期存在。UNIX的管理员们常常用shell去写一些简单的脚本,以进行一些系统维护的工作,比如定期备份、文件系统管理等等。shell可以像胶水一样,将UNIX下的许多功能连接在一起。许多C语言下上百行的程序,在shell下只用几行就可以完成。然而,shell的本质是调用命令。它并不是一个真正的语言。比如说,shell没有数值型的数据类型,加法运算都很复杂。总之,shell不能全面的调动计算机的功能。

Guido希望有一种语言,这种语言能够像C语言那样,能够全面调用计算机的功能接口,又可以像shell那样,可以轻松的编程。ABC语言让Guido看到希望。ABC是由荷兰的数学和计算机研究所开发的。Guido在该研究所工作,并参与到ABC语言的开发。ABC语言以教学为目的。与当时的大部分语言不同,ABC语言的目标是“让用户感觉更好”。ABC语言希望让语言变得容易阅读,容易使用,容易记忆,容易学习,并以此来激发人们学习编程的兴趣。比如下面是一段来自Wikipedia的ABC程序,这个程序用于统计文本中出现的词的总数:

  

HOW TO RETURN words document:

  PUT {} IN collection

  FOR lineIN document:

 FOR wordIN split line:

IF wordnot.in collection:

   INSERT word IN collection

  RETURN collection

 

HOW TO用于定义一个函数。一个Python程序员应该很容易理解这段程序。ABC语言使用冒号和缩进来表示程序块。行 尾没有分号。for和if结构中也没有括号() 。赋值采用的是PUT,而不是更常见的等号。这些改动让ABC程序读起来像一段文字。 尽管已经具备了良好的可读性和易用性,ABC语言最终没有流行起来。在当时,ABC语言编译器需要比较高配置的电脑才能运行。而这些电脑的使用者通常精通计算机,他们更多考虑程序的效率,而非它的学习难度。除了硬件上的困难外,ABC语言的设计也存在一些致命的问题: 可拓展性差。ABC语言不是模块化语言。如果想在ABC语言中增加功能,比如对图形化的支持,就必须改动很多地方。不能直接进行IO。ABC语言不能直接操作文件系统。尽管你可以通过诸如文本流的方式导入数据,但ABC无法直接读写文 件。输入输出的困难对于计算机语言来说是致命的。你能想像一个打不开车门的跑车么? 过度革新。ABC用自然语言的方式来表达程序的意义,比如上面程序中的HOW TO 。然而对于程序员来说,他们更习惯 用function或者define来定义一个函数。同样,程序员更习惯用等号来分配变量。尽管ABC语言很特别,但学习难度 也很大。 传播困难。ABC编译器很大,必须被保存在磁带上。当时Guido在访问的时候,就必须有一个大磁带来给别人安装ABC编 译器。 这样,ABC语言就很难快速传播。 1989年,为了打发圣诞节假期,Guido开始写Python语言的编译器。Python这个名字,来自Guido所挚爱的电视剧Monty Python's Flying Circus。他希望这个新的叫做Python的语言,能符合他的理想:创造一种C和shell之间,功能全面,易学易用,可拓展的语言。Guido作为一个语言设计爱好者,已经有过设计语言的尝试。

1.1.2 Python诞生

1991年,第一个Python编译器诞生。它是用C语言实现的,并能够调用C语言的库文件。从一出生,Python已经具有了 :类,函数,异常处理,包含表和词典在内的核心数据类型,以及模块为基础的拓展系统。 Python语法很多来自C,但又受到ABC语言的强烈影响。来自ABC语言的一些规定直到今天还富有争议,比如强制缩进。 但这些语法规定让Python容易读。另一方面,Python聪明的选择服从一些惯例,特别是C语言的惯例,比如回归等号赋值。Guido认为,如果“常识”上确立的东西,没有必要过度纠结。 Python从一开始就特别在意可拓展性。Python可以在多个层次上拓展。从高层上,你可以直接引入. py文件。在底层,你可以引用C语言的库。Python程序员可以快速的使用Python写. py文件作为拓展模块。但当性能是考虑的重要因素时,Python程序员可以深入底层,写C程序,编译为.so文件引入到Python中使用。Python就好像是使用钢构建房一样,先规定好大的框架。而程序员可以在此框架下相当自由的拓展或更改。 最初的Python完全由Guido本人开发。Python得到Guido同事的欢迎。他们迅速的反馈使用意见,并参与到Python的改进。Guido和一些同事构成Python的核心团队。他们将自己大部分的业余时间用于hack Python。随后,Python拓展到研究所之外。Python将许多机器层面上的细节隐藏,交给编译器处理,并凸显出逻辑层面的编程思考。Python程序员可以花更多的时间用于思考程序的逻辑,而不是具体的实现细节。这一特征吸引了广大的程序员。Python开始流行。

 

1.1.3 时势造英雄

我们不得不暂停我们的Python时间,转而看一看瞬息万变的计算机行业。1990年代初,个人计算机开始进入普通家庭。Intel发布了486处理器,windows发布window 3.0开始的一系列视窗系统。计算机的性能大大提高。程序员开始关注计算机的易用性,比如图形化界面。

 

(Windows 3.0)

由于计算机性能的提高,软件的世界也开始随之改变。硬件足以满足许多个人电脑的需要。硬件厂商甚至渴望高需求软件的出现,以带动硬件的更新换代。C++和Java相继流行。C++和Java提供了面向对象的编程范式,以及丰富的对象库。在牺牲了一定的性能的代价下,C++和Java大大提高了程序的产量。语言的易用性被提到一个新的高度。我们还记得 ,ABC失败的一个重要原因是硬件的性能限制。从这方面说,Python要比ABC幸运许多。硬件性能不是瓶颈,Python又容易使用,所以许多人开始转向Python。Guido维护了一个maillist,Python用户就通过邮件进行交流。Python用户来自许多领域,有不同的背景,对Python也有不同的需求。Python相当的开放,又容 易拓展,所以当用户不满足于现有功能,很容易对Python进行拓展或改造。随后,这些用户将改动发给Guido,并由Gu ido决定是否将新的特征加入到Python或者标准库中。如果代码能被纳入Python自身或者标准库,这将极大的荣誉。由于Guido至高无上的决定权,他因此被称为“终身的仁慈独裁者”。 Python被称为“Battery Included”,是说它以及其标准库的功能强大。这些是整个社区的贡献。Python的开发者来自不同领域,他们将不同领域的优点带给Python。比如Python标准库中的正则表达是参考Perl,而lambda, map, filter, reduce等函数参考了Lisp。Python本身的一些功能以及大部分的标准库来自于社区。Python的社 区不断扩大,进而拥有了自己的newsgroup,网站,以及基金。从Python 2.0开始,Python也从maillist的开发方式,转为完全开源的开发方式。社区气氛已经形成,工作被整个社区分担,Python也获得了更加高速的发展。 到今天,Python的框架已经确立。Python语言以对象为核心组织代码,支持多种编程范式,采用动态类型,自动进行内存回收。Python支持解释运行,并能调用C库进行拓展。Python有强大的标准库。由于标准库的体系已经稳定,所以Python的生态系统开始拓展到第三方包。这些包,如Django、web.py、wxpython、numpy、matplotlib、PIL,将Python升级成了物种丰富的热带雨林。

1.1.4 启示录

Python崇尚优美、清晰、简单,是一个优秀并广泛使用的语言。Python在TIOBE排行榜中排行第八,它是Google的第三大开发语言,Dropbox的基础语言,豆瓣的服务器语言。Python的发展史可以作为一个代表,带给我许多启示。 在Python的开发过程中,社区起到了重要的作用。Guido自认为自己不是全能型的程序员,所以他只负责制订框架。如果问题太复杂,他会选择绕过去,也就是cut the corner。这些问题最终由社区中的其他人解决。社区中的人才是异常丰富的,就连创建网站,筹集基金这样与开发稍远的事情,也有人乐意于处理。如今的项目开发越来越复杂,越来越庞大,合作以及开放的心态成为项目最终成功的关键。 Python从其他语言中学到了很多,无论是已经进入历史的ABC,还是依然在使用的C和Perl,以及许多没有列出的其他 语言。可以说,Python的成功代表了它所有借鉴的语言的成功。同样,Ruby借鉴了Python,它的成功也代表了Python某些方面的成功。每个语言都是混合体,都有它优秀的地方,但也有各种各样的缺陷。同时,一个语言“好与不好”的评 判,往往受制于平台、硬件、时代等等外部原因。程序员经历过许多语言之争。其实,以开放的心态来接受各个语言,说不定哪一天,程序员也可以如Guido那样,混合出自己的语言。

 

(2017年1月份 编程语言流行排行榜)

1.1.5 Python优缺点

优点:

l 简单————Python是一种代表简单主义思想的语言。阅读一个良好的Python程序就感觉像是在读英语一样,尽管这个英语的要求非常严格!Python的这种伪代码本质是它最大的优点之一。它使你能够专注于解决问题而不是去搞明白语言本身。

l 易学————就如同你即将看到的一样,Python极其容易上手。前面已经提到了,Python有极其简单的语法。

l 免费、开源————Python是FLOSS(自由/开放源码软件)之一。简单地说,你可以自由地发布这个软件的拷贝、阅读它的源代码、对它做改动、把它的一部分用于新的自由软件中。FLOSS是基于一个团体分享知识的概念。这是为什么Python如此优秀的原因之一——它是由一群希望看到一个更加优秀的Python的人创造并经常改进着的。

l 高层语言————当你用Python语言编写程序的时候,你无需考虑诸如如何管理你的程序使用的内存一类的底层细节。

l 可移植性————由于它的开源本质,Python已经被移植在许多平台上(经过改动使它能够工作在不同平台上)。如果你小心地避免使用依赖于系统的特性,那么你的所有Python程序无需修改就可以在下述任何平台上面运行。这些平台包括Linux、Windows、FreeBSD、Macintosh、Solaris、OS/2、Amiga、AROS、AS/400、BeOS、OS/390、z/OS、Palm OS、QNX、VMS、Psion、Acom RISC OS、VxWorks、PlayStation、Sharp Zaurus、Windows CE甚至还有PocketPC、Symbian以及Google基于linux开发的Android平台!

l 解释性————这一点需要一些解释。一个用编译性语言比如C或C++写的程序可以从源文件(即C或C++语言)转换到一个你的计算机使用的语言(二进制代码,即0和1)。这个过程通过编译器和不同的标记、选项完成。当你运行你的程序的时候,连接/转载器软件把你的程序从硬盘复制到内存中并且运行。而Python语言写的程序不需要编译成二进制代码。你可以直接从源代码运行程序。在计算机内部,Python解释器把源代码转换成称为字节码的中间形式,然后再把它翻译成计算机使用的机器语言并运行。事实上,由于你不再需要担心如何编译程序,如何确保连接转载正确的库等等,所有这一切使得使用Python更加简单。由于你只需要把你的Python程序拷贝到另外一台计算机上,它就可以工作了,这也使得你的Python程序更加易于移植。

l 面向对象————Python既支持面向过程的编程也支持面向对象的编程。在“面向过程”的语言中,程序是由过程或仅仅是可重用代码的函数构建起来的。在“面向对象”的语言中,程序是由数据和功能组合而成的对象构建起来的。与其他主要的语言如C++和Java相比,Python以一种非常强大又简单的方式实现面向对象编程。

l 可扩展性————如果你需要你的一段关键代码运行得更快或者希望某些算法不公开,你可以把你的部分程序用C或C++编写,然后在你的Python程序中使用它们。

l 丰富的库————Python标准库确实很庞大。它可以帮助你处理各种工作,包括正则表达式、文档生成、单元测试、线程、数据库、网页浏览器、CGI、FTP、电子邮件、XML、XML-RPC、HTML、WAV文件、密码系统、GUI(图形用户界面)和其他与系统有关的操作。记住,只要安装了Python,所有这些功能都是可用的。这被称作Python的“功能齐全”理念。除了标准库以外,还有许多其他高质量的库,如wxPython、Twisted和Python图像库等等。

l 规范的代码————Python采用强制缩进的方式使得代码具有极佳的可读性。

缺点:

l 运行速度,有速度要求的话,用C++改写关键部分吧。

l 国内市场较小。

l 中文资料匮乏。

1.1.6 Python应用场景

l Web应用开发。Python经常被用于Web开发。比如,通过mod_wsgi模块,Apache可以运行用Python编写的Web程序。Python定义了WSGI标准应用接口来协调Http服务器与基于Python的Web程序之间的通信。一些Web框架,如Django,TurboGears,web2py,Zope等,可以让程序员轻松地开发和管理复杂的Web程序。

l 操作系统管理、服务器运维的自动化脚本。在很多操作系统里,Python是标准的系统组件。 大多数Linux发行版以及NetBSD、OpenBSD和Mac OS X都集成了Python,可以在终端下直接运行Python。Python标准库包含了多个调用操作系统功能的库。通过pywin32这个第三方软件包,Python能够访问Windows的COM服务及其它Windows API。使用IronPython,Python程序能够直接调用.Net Framework。一般说来,Python编写的系统管理脚本在可读性、性能、代码重用度、扩展性几方面都优于普通的shell脚本。

l 科学计算。NumPy,SciPy,Matplotlib可以让Python程序员编写科学计算程序。

l 桌面软件。PyQt、PySide、wxPython、PyGTK是Python快速开发桌面应用程序的利器。

l 服务器软件(网络软件).Python对于各种网络协议的支持很完善,因此经常被用于编写服务器软件、网络爬虫。

l 游戏。很多游戏使用C++编写图形显示等高性能模块,而使用Python或者Lua编写游戏的逻辑、服务器。相较于Python,Lua的功能更简单、体积更小;而Python则支持更多的特性和数据类型。

l 构思实现,产品早期原型和迭代。YouTube、Google、Yahoo!、NASA都在内部大量地使用Python。

 

1.1.7 Py2.x 与3.x版本简介

目前市场上有两个 Python 的版本并存着,分别是 Python 2.x 和 Python 3.x:

# 使用 python 2.x解释器

$ python xxx.py

 

# 使用 python 3.x解释器

$ python3 xxx.py

新的 Python 程序建议使用 Python 3.0 版本的语法

Python 2.x 是 过去的版本,解释器名称是 python.

Python 3.x 是 现在和未来 主流的版本,解释器名称是 python3.

相对于 Python 的早期版本,这是一个 较大的升级.为了不带入过多的累赘,Python 3.0 在设计的时候 没有考虑向下兼容.许多早期 Python 版本设计的程序都无法在 Python 3.0 上正常执行.

Python 3.0 发布于 2008 年,到目前为止,Python 3.0 的稳定版本已经有很多年了:

Python 3.3 发布于 2012

Python 3.4 发布于 2014

Python 3.5 发布于 2015

Python 3.6 发布于 2016

为了照顾现有的程序,官方提供了一个过渡版本 —— Python 2.6,基本使用了 Python 2.x 的语法和库,同时考虑了向 Python 3.0 的迁移,允许使用部分 Python 3.0 的语法与函数.

2010 年中推出的 Python 2.7 被确定为 最后一个Python 2.x 版本.

提示:如果开发时,无法立即使用 Python 3.0(还有极少的第三方库不支持 3.0 的语法),建议:

先使用 Python 3.0 版本进行开发.

然后使用 Python 2.6、Python 2.7 来执行,并且做一些兼容性的处理.

 

1.1.8 Python的解释器

Python 的解释器 如今有多个语言的实现,包括:

CPython —— 官方版本的 C 语言实现

Jython —— 可以运行在 Java 平台

IronPython —— 可以运行在 .NET 和 Mono 平台

PyPy —— Python 实现的,支持 JIT 即时编译

 

1.2  Python Hello World

1.2.1 执行python三种方式

1.2.1.1 文本模式

Python代码 保存在文件 中,解释器对文件逐行解释执行,在终端中输入解释器名,再输入要执行的文件名:

# 使用 python 2.x 以文本模式执行python程序

$ python xxx.py

 

1.2.1.2 交互模式

直接在终端中运行解释器,而不输入要执行的文件名。在 Python 交互模式 中 边输入边执行 Python代码,会立即看到程序执行结果。

然而交互模式适合于学习/验证 Python 语法或者局部代码,但是代码不能保存,不太适合运行太大的程序。

当我们想要退出交互模式,可以输出”exit()”.或者使用热键”ctrl+d”来退出交互模式。

    如果我们使用交互模式 编程python程序,除了使用默认的python shell之外呢?我们还可以使用一个功能更强大的交互式 shell,叫IPython ,“I”代表interactive交互的意思。

IPython支持自动补全自动缩进支持 linux命令内置了许多很有用的功能和函数

Python 2.x 使用的解释器是 ipython

Python 3.x 使用的解释器是 ipython3

IPython 的安装: sudo apt install ipython

1.2.1.1 Python IDE(继承开发环境) - PyCharm

什么叫集成开发环境呢?

集成开发环境(IDE,Integrated Development Environment)—— 集成了开发软件需要的所有工具,一般包括以下工具:

l 图形用户界面;

l 代码编辑器(支持 代码补全/自动缩进);

l 编译器/解释器;

l 调试器(断点/单步执行)

l 其他...

 

1.2.2 Pycharm简单介绍

1.2.2.1 简单介绍

PyCharm 是 Python 的一款非常优秀的集成开发环境,PyCharm 除了具有一般 IDE 所必备功能外,还可以在 Windows、Linux、macOS 下使用。

PyCharm 适合开发大型项目,一个项目通常会包含 很多源文件,每个源文件的代码行数是有限的,通常在几百行之内,每个源文件各司其职,共同完成复杂的业务功能。

1.2.2.2 快速体验

 

文件导航区域 能够浏览/定位/打开 项目文件。

文件编辑区域 能够编辑 当前打开的文件。

控制台区域 能够:输出程序执行内容,跟踪调试代码的执行。

 

1.2.3 Hello World程序

1.2.3.1 Python 源程序的基本概念

Python 源程序就是一个特殊格式的文本文件,可以使用任意文本编辑软件做 Python 的开发。

Python 程序的 文件扩展名 通常都是 .py。

1.2.3.2 演练步骤

1. 在pycharm中创建01-HelloPython项目

2. 在项目中创建01-HelloPython.py文件

3. 在01-HelloPython中输入python代码

4. 点击执行

1.2.4 演练扩展

1.2.4.1 关于BUG

bug 原意为 臭虫,在计算机领域,指导致程序不能正常执行,或者执行结果不是预期的错误。BUG是程序员在开发时非常常见的,初学者常见错误的原因包括:

l 手误

l 对已经学习过的知识理解还存在不足

l 对语言还有需要学习和提升的内容

 

在学习语言时,不仅要 学会语言的语法,而且还要 学会如何认识错误和解决错误的方法。

每一个程序员都是在不断地修改错误中成长的。

 

1.2.4.2 手误

1> 手误,例如使用 pirnt("Hello world")

NameError: name 'pirnt' is not defined

名称错误:'pirnt' 名字没有定义

 

2> 将多条 print 写在一行

SyntaxError: invalid syntax

语法错误:语法无效

1.2.4.3 缩进错误

IndentationError: unexpected indent

缩进错误:不期望出现的缩进

Python 是一个格式非常严格的程序设计语言,目前而言,大家记住每行代码前面都不要增加空格。

1.2.4.4 Python2.x默认不支持中文

前市场上有两个 Python 的版本并存着,分别是 Python 2.x 和 Python 3.x。

Python 2.x 默认不支持中文,具体原因,等到介绍字符编码时给大家讲解。

Python 2.x 的解释器名称是 python

Python 3.x 的解释器名称是 python3

python程序中,中文支持:

如果在程序中用到了中文,比如:print('你好'),如果直接运行输出会出错:

SyntaxError: Non-ASCII character'\xe5' in file index.py on line2, but no encoding declared; seehttp://www.python.org/peps/pep-0263.html for details

    解决的办法为:在程序的开头写入如下代码,这就是中文注释:

#coding=utf-8

注意:在python的语法规范中推荐使用的方式:

# -*- coding:utf-8 -*-

 

1.2.4.5 单词列表

* error 错误

* name 名字

* defined 已经定义

* syntax 语法

* invalid 无效

* Indentation 索引

* unexpected 意外的,不期望的

* character 字符

* line 行

* encoding 编码

* declared 声明

* details 细节,详细信息

* ASCII 一种字符编码

 

1.2.4.6 多文件演练

1. 在我们新建的项目01-HelloPython项目中,新增一个程序02-MyPython.py文件

2. 在新文件中添加一句print(“hello python2”)

3. 点击执行新建文件

1.2.5 程序执行原理

1.2.5.1 计算机中的三大件

计算机中包含有较多的硬件,但是一个程序要运行,有 三个 核心的硬件,分别是:

CPU

中央处理器,是一块超大规模的集成电路

负责 处理数据/计算

内存

临时 存储数据(断电之后,数据会消失)

速度快

空间小(单位价格高)

硬盘

永久 存储数据

速度慢

空间大(单位价格低)

 

 

 

思考题:

l 计算机中哪一个硬件设备负责执行程序?

CPU

l 内存 的速度快还是硬盘的速度快?

内存

l 我们的程序是安装在内存中的,还是安装在硬盘中的?

硬盘

l 我买了一个内存条,有 500G 的空间!!!,这句话对吗?

不对,内存条通常只有 4G / 8G / 16G / 32G

l 计算机关机之后,内存中的数据都会消失,这句话对吗?

正确

 

1.2.5.2 程序执行原理

 

程序 运行之前,程序是保存在硬盘中的,当要运行一个程序时,操作系统会首先让 CPU 把程序复制到内存中,CPU 执行内存中的程序代码,程序要执行,首先要被加载到内存。

1.2.5.3 python程序执行原理

 

操作系统会首先让 CPU 把 Python 解释器 的程序复制到内存中,Python 解释器 根据语法规则,从上向下 让 CPU 翻译 Python 程序中的代码,CPU 负责执行翻译完成的代码。

Python 的解释器有多大?

执行以下终端命令可以查看 Python 解释器的大小

# 1. 确认解释器所在位置

$ which python

# 2. 查看 python 文件大小(只是一个软链接)

$ ls -lh /usr/bin/python

# 3. 查看具体文件大小

$ ls -lh /usr/bin/python2.7

提示:建立 软链接的目的,是为了方便使用者不用记住使用的解释器是 哪一个具体版本。

1.2.5.4 程序的作用

程序就是 用来处理数据的!

新闻软件 提供的新闻内容、评论…… 是数据

电商软件 提供的商品信息、配送信息…… 是数据

运动类软件 提供的运动数据…… 是数据

地图类软件 提供的地图信息、定位信息、车辆信息…… 是数据

即时通讯软件 提供的聊天信息、好友信息…… 是数据

1.3  注释

1.3.1 注释概念

看以下程序示例(未使用注释)

 

看以下程序示例(未使用注释)

 

通过用自己熟悉的语言,在程序中对某些代码进行标注说明,这就是注释的作用,能够大大增强程序的可读性。

1.3.2 注释分类

单行注释

以#开头,#右边的所有东西当做说明,而不是真正要执行的程序,起辅助说明作用:

格式为: #+空格+说明

如果在代码之后添加注释: 代码+两个空格+#+空格+说明

# 我是注释,可以在里写一些功能说明之类的哦

print('hello world')

 

多行注释

如果我们编写的注释信息很多,一行无法显示,就使用多行注释,要在python中使用多行注释,可以使用一对连续的三个引号(双引号和单引号):

'''我是多行注释,可以写很多很多行的功能说明

这就是我牛X指出

哈哈哈。。。

'''

'''

下面的代码完成 ,打印一首诗

名字叫做:春江花月夜

作者,忘了

'''

print('╔═╤═╤═╤═╤═╤═╤═╤═╤═╤═╤═╤═╤═╤═╤═╤═╤═╤═╤═╤═╗')

print('║ │春│滟│江│空│江│江│人│不│白│谁│可│玉│此│鸿│昨│江│斜│不│ ║')

print('╚═╧═╧═╧═╧═╧═╧═╧═╧═╧═╧═╧═╧═╧═╧═╧═╧═╧═╧═╧═╝')

 

1.3.3 何时使用注释

l 注释不是越多越好,对于一目了然的代码,不需要添加注释。

l 对于复杂的操作,应该在操作开始前写上若干行注释。

l 对于不是一目了然的代码,应在其行尾添加注释(为了提高可读性,注释应该至少离开代码 2 个空格)。

l 绝不要描述代码,假设阅读代码的人比你更懂 Python,他只是不知道你的代码要做什么。

l 在一些正规的开发团队,通常会有 代码审核 的惯例,就是一个团队中彼此阅读对方的代码。

 

关于代码规范

Python 官方提供有一系列 PEP(Python Enhancement Proposals) 文档

其中第 8 篇文档专门针对 Python 的代码格式 给出了建议,也就是俗称的 PEP 8

文档地址:https://www.python.org/dev/peps/pep-0008/

谷歌有对应的中文文档: http://zh-google-styleguide.readthedocs.io/en/latest/google-python-styleguide/python_style_rules/

1.4  变量及类型

1.4.1 变量的定义

在程序中,有时我们需要对2个数据进行求和,那么该怎样做呢?

大家类比一下现实生活中,比如去超市买东西,往往咱们需要一个菜篮子,用来进行存储物品,等到所有的物品都购买完成后,在收银台进行结账即可。

如果在程序中,需要把2个数据,或者多个数据进行求和的话,那么就需要把这些数据先存储起来,然后把它们累加起来即可。

在Python中,存储一个数据,需要一个叫做变量的东西,如下示例:

 

num1 = 100 #num1就是一个变量,就好一个小菜篮子

num2 = 87  #num2也是一个变量

result = num1+ num2#把num1和num2这两个"菜篮子"中的数据进行累加,然后放到result变量中

说明:所谓变量,可以理解为菜篮子,如果需要存储多个数据,最简单的方式是有多个变量,当然了也可以使用一个。程序就是用来处理数据的,而变量就是用来存储数据的

想一想:我们应该让变量占用多大的空间,保存什么样的数据?

1.4.2 变量的类型

生活中类型的例子:

 

程序中:为了更充分的利用内存空间以及更有效率的管理内存,变量是有不同的类型的,如下所示:

 

怎样知道一个变量的类型呢?在python中,只要定义了一个变量,而且它有数据,那么它的类型就已经确定了,不需要咱们开发者主动的去说明它的类型,系统会自动辨别

可以使用type(变量的名字),来查看变量的类型.

1.4.3 变量使用演练

 

苹果的价格是 8.5 元/斤,买了 7.5斤苹果,计算付款金额?

price = 8.5

 

# 定义购买重量

weight = 7.5

 

# 计算金额

money = price* weight

 

print(money)

思考题,如果只要买苹果,就返5块钱,请重新计算购买金额?

# 定义苹果价格变量

price = 8.5

 

# 定义购买重量

weight = 7.5

 

# 计算金额

money = price* weight

 

# 只要买苹果就返 5 元

money = money- 5

print(money)

提问:

上述代码中,一共定义有几个变量?

3个:price/weight/money

money = money - 5 是在定义新的变量还是在使用变量?

直接使用之前已经定义的变量,变量名只有在 第一次出现 才是定义变量.变量名再次出现,不是定义变量,而是直接使用之前定义过的变量

在程序开发中,可以修改之前定义变量中保存的值吗?

可以

变量中存储的值,就是可以变的.

1.4.4 变量类型演练

定义变量保存小明的个人信息

姓名:小明

年龄:18 岁

性别:是男生

身高:1.75 米

体重:75.0 公斤

 

提示:可以通过type查看变量类型。

1.5  标识符和关键字

1.5.1 标识符概念

 

开发人员在程序中自定义的一些符号和名称。标示符是自己定义的,如变量名,函数名等。

1.5.2 标识符规则

标示符由字母、下划线和数字组成,且数字不能开头

思考:下面那些是正确的,那些是不正确的:

fromNo12

from#12

my_Boolean

my-Boolean

Obj2

2ndObj

myInt

test1

Mike2jack

My_tExt

_test

test!32

haha(da)tt

int

jack_rose

jack&rose

GUI

G.U.I

 

注意:python中的标识符是区分大小写的.

 

1.5.3 命名规则

见名知意。起一个有意义的名字,尽量做到看一眼就知道是什么意思(提高代码可 读性) 比如: 名字 就定义为 name , 定义学生 用 student。

驼峰命名法:

 

l 小驼峰式命名法(lower camel case): 第一个单词以小写字母开始;第二个单词的首字母大写,例如:myName、aDog

l 大驼峰式命名法(upper camel case): 每一个单字的首字母都采用大写字母,例如:FirstName、LastName

l 不过在程序员中还有一种命名法比较流行,就是用下划线“_”来连接所有的单词,比如send_buf  

1.5.4 关键字

什么是关键字?

python一些具有特殊功能的标示符,这就是所谓的关键字。是python已经使用的了,所以不允许开发者自己定义和关键字相同的名字的标示符。

查看关键字:

and     as      assert     break     class      continue    def     del

elif    else    except     exec      finally    for         from    global

if      in      import     is        lambda     not         or      pass

print   raise   return     try       while      with        yield

可以通过以下命令进行查看当前系统中python的关键字:

 

import keyword

keyword.kwlist

关键字的学习以及使用,咱们会在后面的课程中依依进行学习.

1.5.5 不同变量之间计算

1.5.5.1 数字类型变量计算

l 在Python中两个数字型变量之间可以直接进行算数运算。

l 如果是Bool类型,那么True对应数字1,False对应数字0。

 

演练步骤:

定义整数i = 10

定义浮点数 f = 10.5

定义Bool类型 b = True

在程序中对上述变量进行算数运算。

 

1.5.5.2 字符串类型变量计算

在Python中可以使用+号拼接两个字符串,可以使用*重复拼接相同的字符串。除此之外,字符串和数字不能进行其他的运算。

演练:

First_name = “Edward”

Last_name = “Meng”

 

1.6  输出

1.6.1 普通输出

# 打印提示

print('hello world')

print('给我的卡---印度语,你好的意思')

1.6.2 格式化输出

l 我们知道在Python中我们可以使用print函数向控制台输出信息;

l 如果我们想输出信息的同时,一起输出数字,就需要使用格式化操作符

l %被成为格式化操作符,专门用于格式化输出,也就是说包含%的字符串,被成为格式化字符串。%需要和不同的字符连用,不同类型的数据,需要使用不同的格式化字符。

l 使用格式为:

print(“格式化字符串” %变量)

print(“格式化字符串” %(变量1,变量2))

 

课堂演练:

l 定义字符串变量name,输出“我的名字叫小明,请多多关照”

l 定义整数变量stu_no,输出“我的学号是10001”

l 定义小数price、weight、money,输出“苹果单价9.00元/斤,购买了5斤,需要支付45.00元”

l 定义一个小数,输出“数据比例是10%”

 

age = 10

print("我今年%d岁"%age)

 

age += 1

print("我今年%d岁"%age)

 

age += 1

print("我今年%d岁"%age)

在程序中,看到了%这样的操作符,这就是Python中格式化输出。

age = 18

name = "xiaohua"

print("我的姓名是%s,年龄是%d"%(name,age))

 

常用的格式符号:

格式符号转换

%s通过str() 字符串转换来格式化

%d 整数输出

%o八进制整数

%x十六进制整数(小写字母)

%f浮点实数,%.2f表示输出小数后两位

%% 输出%号

 

换行输出:

在输出的时候,如果有\n那么,此时\n后的内容会在另外一行显示。

print("1234567890-------") #会在一行显示

print("1234567890\n-------") #一行显示1234567890,另外一行显示-------

1.6.3 练一练

编写代码完成以下名片的显示

==================================

姓名: itcast    

QQ:xxxxxxx

手机号:131xxxxxx

公司地址:北京市xxxx

==================================

 

1.7  输入

 

咱们在银行ATM机器前取钱时,肯定需要输入密码,对不?那么怎样才能让程序知道咱们刚刚输入的是什么呢??大家应该知道了,如果要完成ATM机取钱这件事情,需要先从键盘中输入一个数据,然后用一个变量来保存,是不是很好理解。

简单来讲,所谓输入就是通过代码方式获取用户键盘输入的信息。在Python中获取用户输入需要使用input函数。

说到函数,那什么是函数呢?函数就是一个提前准备好的功能(别人或者自己写好的代码),可以直接使用,而不用关心函数实现的细节。目前我们已经学完的函数,print(x),type(x)等等。

1.7.1 raw_input

在Python中,获取键盘输入的数据的方法是采用 raw_input函数,那么这个 raw_input 怎么用呢?需要注意的是,用户输入的任何内容Python都认为是一个字符串

看如下示例:

password = raw_input("请输入密码:")

print '您刚刚输入的密码是:', password

注意:

raw_input()的小括号中放入的是,提示信息,用来在获取数据之前给用户的一个简单提示

raw_input()在从键盘获取了数据以后,会存放到等号右边的变量中

raw_input()会把用户输入的任何值都作为字符串来对待

注意:如果使用python3编译,会报错:

NameError: name'raw_input' is not defined

原因是在python3.x中已经废弃raw_input,可以使用input代替.

1.7.2 input

input()函数与raw_input()类似,在python2中接受的输入必须是表达式。python3中可接收任何输入.

a = 10

b = 20

#password = raw_input("请输入密码:\n")

password = input("请输入密码:\n")

print("您输入的密码是:%s"% password)

print(type(password))

1.7.3类型转换函数

在我们上例程序中,如果我们希望记录用户的输入,可以使用input函数,但是input记录下来的数据类型是字符串类型的,那么假如用户输入了int类型的数字,或者float类型的数字,那么默认是字符串的,如何将其进行转换呢?

 

Int(x)

将x转换为int类型

Float(x)

将x转换为float类型

 

加法计算器案例

用户输入左操作数

用户输入有操作数

计算结果,并且输入

 

买苹果案例增强版:

收银员输入苹果的价格,单位:元/斤;

收银员输入苹果的数量,单位:斤;

计算并且输出付款金额;

显示客户剩余金钱

 

1.8  运算符

python支持以下几种运算符:

1.8.1 算术运算符

运算符描述实例

+两个对象相加a + b输出结果 30

-得到负数或是一个数减去另一个数a - b输出结果 -10

*两个数相乘或是返回一个被重复若干次的字符串a * b输出结果 200

/x除以y b/ a输出结果 2

//取整除返回商的整数部分9//2 输出结果4 , 9.0//2.0 输出结果4.0

%取余返回除法的余数b % a输出结果 0

**返回x的y次幂a**b为102次方, 输出结果100

1.8.2 赋值运算符

运算符描述    实例

=赋值运算符=号右边的结果给左边的变量num=1+2*3 结果num的值为7

1.8.3 复合运算符

运算符描述实例

+=加法赋值运算符c+= a等效于 c = c+ a

-=减法赋值运算符c-= a等效于 c = c- a

*=乘法赋值运算符c*= a等效于 c = c* a

/=除法赋值运算符c/= a等效于 c = c/ a

%=取模赋值运算符c%= a等效于 c = c% a  C模A

**=幂赋值运算符c**= a等效于 c = c** a

//=取整除赋值运算符c//= a等效于 c = c// a

 

1.10 分支语句

1.10.1分支概念

 

 

if语句是用来进行判断的,其使用格式如下:

if 要判断的条件:

条件成立时,要做的事情

例子一:

age = 30

print "------if判断开始------"

if age>=18:

print "我已经成年了"

print "------if判断结束------"

例子二:

age = 16

print "------if判断开始------"

if age>=18:

print "我已经成年了"

print "------if判断结束------"

以上2个demo仅仅是age变量的值不一样,结果却不同;能够看得出if判断语句的作用:就是当满足一定条件时才会执行那块代码,否则就不执行那块代码

注意:代码的缩进为一个tab键,或者4个空格

1.10.2关系运算符

比较(即关系)运算符:

运算符描述

==检查两个操作数的值是否相等,如果是则条件变为真。

!=检查两个操作数的值是否相等,如果值不相等,则条件变为真。

<>检查两个操作数的值是否相等,如果值不相等,则条件变为真。(py3废弃)

>检查左操作数的值是否大于右操作数的值,如果是,则条件成立。

<检查左操作数的值是否小于右操作数的值,如果是,则条件成立。

>=检查左操作数的值是否大于或等于右操作数的值,如果是,则条件成立。

<=检查左操作数的值是否小于或等于右操作数的值,如果是,则条件成立。

 

逻辑运算符:

运算符描述

and布尔"与" -> 如果x 为 False,xand y返回 False,否则它返回y 的计算值。

or布尔"或" -> 如果x 是 True,它返回True,否则它返回y 的计算值。

not布尔"非" -> 如果x 为 True,返回False 。如果x 为 False,它返回True

1.10.3 if-else

想一想:在使用if的时候,它只能做到满足条件时要做的事情。那万一需要在不满足条件的时候,做某些事,该怎么办呢?

答:else

if-else的使用格式:

if 条件:

满足条件时要做的事情1

满足条件时要做的事情2

满足条件时要做的事情3

...(省略)...

else:

不满足条件时要做的事情1

不满足条件时要做的事情2

不满足条件时要做的事情3

...(省略)...

1.10.4 elif

想一想:if能完成当xxx时做事情;if-else能完成当xxx时做事情1,否则做事情2;如果有这样一种情况:当xxx1时做事情1,当xxx2时做事情2,当xxx3时做事情3,那该怎么实现呢?

:elif.

elif的使用格式如下:

 if xxx1:

事情1

elif xxx2:

事情2

elif xxx3:

事情3

 

 

说明:

当xxx1满足时,执行事情1,然后整个if结束

当xxx1不满足时,那么判断xxx2,如果xxx2满足,则执行事情2,然后整个if结束

当xxx1不满足时,xxx2也不满足,如果xxx3满足,则执行事情3,然后整个if结束

例子:

score = 77

if score>=90 and score<=100:

print('本次考试,等级为A')

elif score>=80 and score<90:

print('本次考试,等级为B')

elif score>=70 and score<80:

print('本次考试,等级为C')

elif score>=60 and score<70:

print('本次考试,等级为D')

elif score>=0 and score<60:

print('本次考试,等级为E')

注意:可以和else一起使用

if 性别为男性:

   输出男性的特征

   ...

elif 性别为女性:

   输出女性的特征

   ...

else:

   第三种性别的特征

   ...

说明:

当“性别为男性”满足时,执行“输出男性的特征”的相关代码;

当“性别为男性”不满足时,如果“性别为女性”满足,则执行“输出女性的特征”的相关代码;

当“性别为男性”不满足,“性别为女性”也不满足,那么久默认执行else后面的代码,即“第三种性别的特征”相关代码.

elif必须和if一起使用,否则出错.

1.10.5 if嵌套

通过学习if的基本用法,已经知道了,当需要满足条件去做事情的这种情况需要使用if,当满足条件时做事情A,不满足条件做事情B的这种情况使用if-else。

 

想一想:

坐火车或者地铁的实际情况是:先进行安检如果安检通过才会判断是否有车票,或者是先检查是否有车票之后才会进行安检,即实际的情况某个判断是再另外一个判断成立的基础上进行的,这样的情况该怎样解决呢?

答:if嵌套

if嵌套的格式:

if 条件1:

 

满足条件1 做的事情1

满足条件1 做的事情2

...(省略)...

 

if 条件2:

满足条件2 做的事情1

满足条件2 做的事情2

...(省略)...

说明:外层的if判断,也可以是if-else,内层的if判断,也可以是if-else,根据实际开发的情况,进行选择。

案例:

chePiao = 1     # 用1代表有车票,0代表没有车票

daoLenght = 9     # 刀子的长度,单位为cm

if chePiao== 1:

print("有车票,可以进站")

if daoLenght< 10:

print("通过安检")

print("终于可以见到Ta了,美滋滋~~~")

else:

print("没有通过安检")

print("刀子的长度超过规定,等待警察处理...")

else:

print("没有车票,不能进站")

print("亲爱的,那就下次见了,一票难求啊~~~~(>_<)~~~~")

1.10.3 课堂练习

1. 从键盘获取自己的年龄,判断是否大于或者等于18岁,如果满足就输出“哥,已成年,网吧可以去了”

1)使用input从键盘中获取数据,并且存入到一个变量中

2)使用if语句,来判断 age>=18是否成立

2. 从键盘输入刀子的长度,如果刀子长度没有超过10cm,则允许上火车,否则不允许上火车

3. 情节描述:上公交车,并且可以有座位坐下.要求:输入公交卡当前的余额,只要超过2元,就可以上公交车;如果空座位的数量大于0,就可以坐下.

4. 应用:猜拳游戏.

 

1.11 练习作业

1. 说出变量名字,可以由哪些字符组成

2. 写出变量命名时的规则

3. 说出什么是驼峰法(大驼峰、小驼峰)

4. 编写程序,完成以下要求:

提示用户进行输入数据

获取用户的数据数据(需要获取2个)

对获取的两个数字进行求和运行,并输出相应的结果

5. 编写程序,完成以下要求:

提示用户进行输入数据

获取用户的数据数据(需要获取2个)

对获取的两个数字进行减法运行,并输出相应的结果

6. 编写程序,完成以下信息的显示:

    ==================================

    =        欢迎进入到身份认证系统V1.0

    = 1. 登录

    = 2. 退出

    = 3. 认证

    = 4. 修改密码

    ==================================

7. 编写程序,从键盘获取一个人的信息,然后按照下面格式显示

    ==================================

    姓名: itcast    

    QQ:xxxxxxx

    手机号:131xxxxxx

    公司地址:北京市xxxx

    ==================================

8. 编写程序,从键盘获取用户名和密码,然后判断,如果正确就输出以下信息

   亲爱的xxx,欢迎登陆 爱学习管理系统

1.12 循环语句

1.12.1 循环概念

 

软件开发中循环的使用场景:

跟媳妇承认错误,说一万遍"媳妇儿,我错了":

print("媳妇儿,我错了")

print("媳妇儿,我错了")

print("媳妇儿,我错了")

...(还有99997)...

使用循环语句一句话搞定:

i = 0

while i<10000:

print("媳妇儿,我错了")

i+=1

 

一般情况下,需要多次重复执行的代码,都可以用循环的方式来完成.循环不是必须使用的,但是为了提高代码的重复使用率,所以有经验的开发者都会采用循环.

在程序开发中,一共有三种流程方式:

顺序 —— 从上向下,顺序执行代码

分支 —— 根据条件判断,决定执行代码的 分支

循环 —— 让 特定代码 重复 执行

 

 

1.12.2 while循环

循环的作用就是让 指定的代码重复的执行

while 循环最常用的应用场景就是 让执行的代码 按照 指定的次数 重复 执行

需求 —— 打印 5 遍 Hello Python

思考 —— 如果要求打印 100 遍怎么办?

while循环的格式:

 while 条件:

        条件满足时,做的事情1

        条件满足时,做的事情2

        条件满足时,做的事情3

        ...(省略)...

 

i = 0

while i<5:

print("当前是第%d次执行循环"%(i+1))

print("i=%d"%i)

i+=1

输出:

当前是第1次执行循环

i=0

当前是第2次执行循环

i=1

当前是第3次执行循环

i=2

当前是第4次执行循环

i=3

当前是第5次执行循环

i=4

 

1.12.3 while应用

1. 计算1~100的累积和(包含1和100):

#encoding=utf-8

 

i = 1

sum = 0

while i<=100:

    sum = sum+ i

    i += 1

 

print("1~100的累积和为:%d"%sum)

2. 计算1~100之间偶数的累积和(包含1和100):

#encoding=utf-8

 

i = 1

sum = 0

while i<=100:

    if i%2 == 0:

        sum = sum+ i

    i+=1

 

print("1~100的累积和为:%d"%sum)

1.12.4 while案例

创建用户,用户有名字和金钱账户,每次参与押注,押注猜中,所压金钱翻倍,未猜中,则从账户中扣除押注数额,账户金额小于0,Game Over退出程序:

 #!/usr/bin/python

 # -*- coding:utf-8 -*-

 

 import random

 

 #初始化用户名字

 name=input("请输入您的名字:\n")

 #初始化账户100块钱

 acount = 100

 

 print("\t拉斯维加斯世界赌王争霸赛\t")

 print("比赛正式开始...\n")

 while acount> 0:

         #输入本次押注的金额

         money = input("请输入压住金额:")

         #判断用户账户余额是否够押注

         if int(money) > acount:

                 print("余额不足,请重新押注!\n")

                 print("您的余额:%d\n"%(acount))

         else:

                 #输入押注的数字

                 number = input("请输入押注数字(1-10):")

                 #检测押注数字是否在1-10

                 if int(number) > 0 and int(number) <= 10:

                         #开盅

                         dice = random.randint(1,10)

                         print("本次开盅数字为:%d,您押注的数字为:%s\n"%(dice,number))

                         if int(number) == dice:

                                 print("恭喜您,本轮押注胜利,获得返还金额:%d"%(int(money)*2))

                                 acount = acount+ int(money) * 2

                         else:

                                 acount = acount- int(money)

                                 print("很遗憾,本轮押注失败,余额为:%d"%(acount))

                 else:

                         print("押注数字应该在1-10,请重新输入:)\n")

 

 print("Game Over!")

1.12.5 while嵌套

前面学习过if的嵌套了,想一想if嵌套是什么样子的?类似if的嵌套,while嵌套就是:while里面还有while。

while嵌套的格式:

while 条件1:

 

条件1满足时,做的事情1

条件1满足时,做的事情2

条件1满足时,做的事情3

...(省略)...

 

while 条件2:

条件2满足时,做的事情1

条件2满足时,做的事情2

条件2满足时,做的事情3

...(省略)...

while嵌套应用一:

'''

打印效果:

*

* *

* * *

* * * *

* * * * *

'''

i = 1

while i<=5:

 

j = 1

while j<=i:

print("* ",end='')

j+=1

 

print("\n")

i+=1

while嵌套应用二:九九乘法表

 

 

i = 1

while i<=9:

j=1

while j<=i:

print("%d*%d=%-2d "%(j,i,i*j),end='')

j+=1

print('\n')

i+=1

1.12.6转义字符

字符串中的转义字符:

\t 在控制台输出一个 制表符,协助在输出文本时垂直方向 保持对齐,但不会换行

\n 在控制台输出一个 换行符

制表符 的功能是在不使用表格的情况下在垂直方向 按列对齐文本

   

\ 反斜杠符号

\' 单引号

\" 双引号

\n 换行

\t 横向制表符

\r 回车

1.12.7 continue和break

break的作用:用来结束整个循环,continue的作用:用来结束本次循环,紧接着执行下一次的循环。

break/continue只能用在循环中,除此以外不能单独使用。

break/continue在嵌套循环中,只对最近的一层循环起作用。

break的使用:

 #!/usr/bin/python

 #-*-coding:utf-8-*-

 

 s = "abcdefg"

 for chin s:

         if ch== 'e':

                 break

         else:

                 print(ch,end=' ')

 #输出换行

 print()

 

 index = 0

 while index< 10:

         if index> 7:

                 break

                 #print("aaa", end=' ')

         else:

                 b = 100

                 print(index,end=' ')

         index = index+ 1

 print()   

continue的使用:

 #!/usr/bin/python

 #-*-coding:utf-8-*-

 import random

 number = random.randint(1,10)

 index = 0

 while index< 10:

         val = input("请输入猜测的数字:")

         if int(val) == int(number) :

                 print("猜对了,获胜!")

                 break;

         else:

                 print("猜错了,请重新输入!")

         index = index+ 1;

 print("正确数字:%s"%number)

 

 

 

1.12.8 分支和循环总结

if往往用来对条件是否满足进行判断:

if有4中基本的使用方法:

l 基本方法

    if 条件:

        满足时做的事情

l 满足与否执行不同的事情

    if 条件:

        满足时做的事情

    else:

        不满足时做的事情

l 多个条件的判断

    if 条件:

        满足时做的事情

    elif 条件2:

        满足条件2时做的事情

    elif 条件3:

        满足条件3时做的事情

    else:

        条件都不满足时做的事情

l 嵌套

    if 条件:

        满足时做的事情

这里还可以放入其他任何形式的if判断语句

l while循环一般通过数值是否满足来确定循环的条件:

      i = 0

      while i<10:

          print("hello")

          i+=1

l for循环一般是对能保存多个数据的变量,进行便利

      name = itcast

      for x in name:

          print(x)

if、while、for等其他语句可以随意组合,这样往往就完成了复杂的功能。

1.13 函数

1.13.1 函数的作用

假如,我的程序中需要频繁使用一个功能,功能是这样的,当我输入一个成绩的时候,需要显示学生的成绩是A,还是B,还是C...那我应该怎么做呢?

stuA_score =int(input("请输入成绩:"))
if stuA_score >=90 andstuA_score <=100:
    print("您的成绩是A!")
elif stuA_score >=80 andstuA_score <90:
    print("您的成绩是B!")
elif stuA_score >=70 andstuA_score <80:
    print("您的成绩是C!")
elif stuA_score >=60 andstuA_score <70:
    print("您的成绩是D!")
else:
    print("您需要努力了!")


stuB_score = int(input("请输入成绩:"))
if stuB_score >=90 andstuB_score <= 100:
    print("您的成绩是A!")
elif stuB_score >=80 andstuB_score < 90:
    print("您的成绩是B!")
elif stuB_score >=70 andstuB_score < 80:
    print("您的成绩是C!")
elif stuB_score >=60 andstuB_score < 70:
    print("您的成绩是D!")
else:
    print("您需要努力了!")

stuC_score = int(input("请输入成绩:"))
if stuC_score >=90 andstuC_score <= 100:
    print("您的成绩是A!")
elif stuC_score >=80 andstuC_score < 90:
    print("您的成绩是B!")
elif stuC_score >=70 andstuC_score < 80:
    print("您的成绩是C!")
elif stuC_score >=60 andstuC_score < 70:
    print("您的成绩是D!")
else:
    print("您需要努力了!")

 

 

从以上代码,你会发现这样的现象,代码重复,如果成绩大于95算是A的话,那么所有使用到这个功能的地方的代码都要修改,很痛苦,很不方便。

所以我们应该通过一种技术来复用代码,这样使用相同功能的地方,我们使用同一段代码,维护量就会降低,而且代码的可读性也会提升不少。那么这种技术是什么呢?函数

通过函数我们的代码就修改为以下:

def show_score(score):
    ifscore >= 90and score <=100:
        print("您的成绩是A!")
    elifscore >= 80and score <90:
        print("您的成绩是B!")
    elifscore >= 70and score <80:
        print("您的成绩是C!")
    elifscore >= 60and score <70:
        print("您的成绩是D!")
    else:
        print("您需要努力了!")

stuA_score = int(input("请输入成绩:"))
show_score(stuA_score)
stuB_score = int(input("请输入成绩:"))
show_score(stuB_score)
stuC_score = int(input("请输入成绩:"))
show_score(stuC_score)

 

函数的作用,就是把常用的功能封装成一个实体,用的时候,直接调用就可以,不需要写重复代码,维护非常容易。

1.13.2 函数定义和调用

函数组成的三要素是:函数名 函数参数返回值

定义函数的格式如下:

 def myAdd(a,b):

     Val = a + b

        return val

 

 

定义了函数之后,就相当于有了一个具有某些功能的代码,想要让这些代码能够执行,需要调用它。调用函数很简单的,通过函数名() 即可完成调用。

# 定义完函数后,函数是不会自动执行的,需要调用它才可以

myAdd()

 

函数参数:

l 函数的参数,增加函数的通用性,针对相同的数据处理逻辑,能够适应更多的数据.

l 在函数内部,把参数当做变量使用,进行需要的数据处理.函数调用时,按照函数定义的参数顺序,把希望在函数内部处理的数据,通过参数传递.

 

形参和实参:

l 形参:定义函数时,小括号中的参数,是用来代替真实数据 用的,在函数内部作为变量使用.

l 实参:调用 函数时,小括号中的参数,是传递到函数内部的真实数据.

 

形参作用域:

l 形参的作用域(起作用的范围)只在定义函数的代码块 中,一旦超出该范围再使用该形参名,则使用的是 同名的自定义变量.

l 编程中应该尽量避免 函数的形参 和 同文件的变量名同名.

 

a =5
def test1(a):
    a += 1
    print("%d"% a)
test1(a)
print("%d"% a)

 

 

返回值:

l 在程序开发中,有时候,会希望 一个函数执行结束后,告诉调用者一个结果,以便调用者针对具体的结果做后续的处理.返回值是函数完成工作后,最后给调用者的一个结果

l 在函数中使用 return 关键字可以返回结果.

l 调用函数一方,可以使用变量来接收函数的返回结果.

 

 

1.13.3 缺省参数

调用函数时,缺省参数的值如果没有传入,则被认为是默认值。下例会打印默认的age,如果age没有被传入.

def printinfo( name, age =35 ):
   #打印任何传入的字符串
   
print"Name: ", name
   print"Age ", age
# 调用printinfo函数
printinfo(name="miki")
printinfo( age=9,name="miki")

 

注意:带有默认值的参数一定要位于参数列表的最后面。

 

1.13.4 多个函数返回值

在python中,我们可以返回多个值。

输入3个参数,返回3个参数中最大值和最小值.

def test(a,b,c):
   min = a
   max = a
   ifb < min:
      min = b
   ifc < min:
      min = c
   ifb > max:
      max = b
   ifc > max:
      max = c
   returnmin,max
min,max = test(200,300,100)
print(min)
print(max)

 

 

1.13.5 局部变量和全局变量

l 局部变量,就是在函数内部定义的变量。

l 不同的函数,可以定义相同的名字的局部变量,但是各用个的不会产生影响。

l 局部变量的作用,为了临时保存数据需要在函数中定义变量来进行存储。

 

 

 

l 函数内部变量定义并且赋值,该变量为局部变量;

l 在函数外部定义的变量,为全局变量;

l 函数内部使用变量名,局部变量名和全局变量名同名,优先使用局部变量;

l 在函数内部如果想要使用全局变量,使用global关键字声明;

l 全局变量在函数内部未声明的情况下,只能使用,不可修改值.

 

 

1.13.7 函数嵌套调用

 

import random

 

# 玩家姓名

playerName = "John"

# 玩家金钱

playerMoney = 1000

 

# 显示玩家信息

def show_player():

    print("玩家姓名:%s玩家余额:%d" % (playerName, playerMoney))

 

# 押注金额和赔率

def bet_on():

 

    money = 0

    rate = 1

    while True:

        money = int(input("请输入押注金额:"))

        # 如果押注金额大于账户余额,则重新输入

        if money > playerMoney:

            print("账户余额:%s,不足以本次押注,请重新输入!" % playerMoney)

        else:

            break

 

    # 计算合理赔率

    right_rate = playerMoney // money

    while True:

        print("请输入赔率(1-%d):" % right_rate, end="")

        rate = int(input())

        if int(rate) < 1 or int(rate) > right_rate:

            print("输入的赔率不正确,请重新输入!")

        else:

            break

 

    return rate, money

 

 

# 赌博

def gamble(rate, money):

    # 随机产生竞猜数字

    guessing_robot = random.randint(1, 6)

    # 输入竞猜数字

    guessing_number = int(input("先生,请输入竞猜数字(1-6):"))

    # 显示竞猜数字

    print("系统产生竞猜数字为:%d,您的竞猜数字为:%d" % (guessing_robot, guessing_number))

    # 比较竞猜数字

    global playerMoney

    if guessing_number == guessing_robot:

        print("恭喜您,本轮猜中!")

        playerMoney = playerMoney + money * (rate - 1)

    else:

        print("抱歉,本轮您未猜中!")

        playerMoney = playerMoney - money * rate

 

 

# 开始游戏

def start_game():

 

    # 当前局数

    game = 1

    while playerMoney > 0:

        print("第%d轮竞猜开始:" % game)

        # 显示玩家信息

        show_player()

        # 押注

        rate, money = bet_on()

        # 开始赌博

        gamble(rate, money)

        game += 1

        print("---------------------")

    show_player()

    print("游戏结束!")

start_game()

 

 

1.14 字符串

当打来浏览器登录某些网站的时候,需要输入密码,浏览器把密码传送到服务器后,服务器会对密码进行验证,其验证过程是把之前保存的密码与本次传递过去的密码进行对比,如果相等,那么就认为密码正确,否则就认为不对;服务器既然想要存储这些密码可以用数据库(比如MySQL),当然为了简单起见,咱们可以先找个变量把密码存储起来即可;那么怎样存储带有字母的密码呢?

答:字符串.

字符串本质是字符序列。Python的字符串是不可修改的。无法对原字符串进行修改,但是可以将字符串的一部分赋值到新字符串,来达到相同的修改效果。

python中字符串的格式:

b1 = "hello itcast.cn"

#或者

b2 = 'hello itcast.cn'

小总结:双引号或者单引号中的数据,就是字符串.

1.14.1 字符串创建和打印

l 将一系列字符包裹在一对单引号或一对双引号中即可创建字符串;为什么要使用两种引号呢?这么做的好处是可以创建本身就包含引号的字符串,而不使用转义符。可以在双引号中包裹单引号字符,也可以在单引号中包裹双引号字符。

l 使用连续三个单引号’’’或者三个”””来创建字符串。三引号在创建短字符串时没有什么用途。它多用于创建多行字符串。在三引号包裹的字符串中,每行的换行符以及行首行末的空格都会被保留。

 

str1 = "aaa"

str2 = 'bbb'

str3 = '''

          123455

          7890

          123ghfhgfd'''

 

1.14.2 字符串运算+和*

在Python中,我们可以使用+将多个字符串或字符串变量拼接起来,也可以直接将一个字符串字面量放到另一个的后面直接实现拼接。

使用*可以进行字符串复制。例如”a” * 5 = “aaaaa”

1.14.3 使用[]提取字符

在字符串名后面添加[],并在括号里指定偏移量可以提取该位置的单个字符。注意:第一个字符的便宜量为0,下一个是1,以此类推。最后一个字符的偏移量可以使用-1来表示,这样就不必从头数到尾。偏移量从右向左紧接着为-2、-3,以此类推。

注意:如果指定的字符串超过了字符串的长度,会得到一个错误提示:string index out of range.

 

再次注意:由于字符串不可修改,所以试图通过[]去修改字符串的行为是错误的。如果我们需要改变字符串,需要使用一些字符串函数,例如str.replace()。

 

字符串打印: while循环+[]、for循环

 

1.14.4 使用[start:end:step]分片(切片)

分片操作可以从一个字符串抽取一个子字符串(字符串的一部分)。我们使用一对方括号,起始偏移量start,和终止偏移量end以及可选的步长step来定义一个分片。其中一些参数可以省略。分片将会得到start开始到end结束之前全部的字符

s = “abcde”

l [:] 提取从开头到结尾的整个字符串;

l [start:] 提取从start开始到结尾的所有字符串;

l [:end] 从开头提取到end-1之间所有字符;

l [start:end] 从start提取到end-1;

l [start:end:step] 从start到end-1,每step个字符提取一个.

 

 

与之前一样,偏移量从左向右从0、1开始,依次增加;从右至左从-1、-2开始,依次减少。如果省略了start,分片会默认使用偏移量0(开头);如果省略了end,分结尾.片默认使用-1

 

注意:分片中end的偏移量需要比实际提取的最后一个字符的偏移量多1

 

 

 

 

1.14.5 字符串操作

到目前位置,我们已经学会了许多特殊的标点符号对字符串进行相应的操作。但是标点符号只有有限的几种。从现在开始,我们将学习使用Python的内置函数。

1.14.5.1 使用len()获得长度

len()函数可用于计算字符串的包含的字符数。例如:len(str)

1.14.5.2 使用split()分割

与len()函数不同,有些函数只适用于字符串类型。为了调用字符串函数,你需要输入字符串的名称、一个点号,需要调用的函数名,以及需要传入的参数:string.function(args).

使用内置的字符串函数split()可以基于分隔符将字符串分割成若干子串组成的列表。所谓list是由一系列值组成的序列,值与值之间用逗号隔开,整个列表被方括号包裹。

例如: s = “ab,cd,ef,ghk”   s.split(“,”)

1.14.5.3 使用find()和rfind()查找子串

使用find()函数可以从左向右查找指定的字符串在既定字符串中的位置,如果存在则返回位置,不存在,则返回-1.

rfind()类似于find()函数,只不过是从右向左查找,也就是查找指定字符串最后一次出现的位置。

 

1.14.5.4 使用startwith()和endwith()

检查字符串是否是以指定字符串开头, 是则返回 True,否则返回False.

检查字符串是否以指定字符串结束,如果是返回True,否则返回False.

 

1.14.5.5 使用replace()替换

使用replace()函数可以将指定的字符串替换其他的字符串,并生成新的字符串。默认情况下,会将字符串所有的指定字符串替换为目标字符串,也可以指定第三个参数,最多替换次数。

例如:

s = "abadeag"

s1 = s.replace("a", "1",2)

print(s1)

 

1.14.5.6 清除字符串两侧字符

将指定收尾字符串都删除掉,可以使用strip()函数,如果不指定字符,默认是删除两侧空格。lstrip()和rstrip()删除左侧和右侧指定字符。

1.14.5.7 字符串对齐

使用center()、ljust()、rjust()可以在指定长度的空间中,居中,左对齐,右对齐。

 

1.14.5.8 字符串大小写

让字符串首字母变成大写可以使用capitalize()函数,让所有的单词的开头字母变成大写,使用title()函数,让所有字母变成大写使用upper()函数,让所有单词变成小写使用lower()函数,

1.14.5.9 使用partition()函数

使用partition(str)函数可以将字符串分成三部分,str之前,str和str之后。

 

1.14.5.10 使用isalpha()和isdigit()函数

isalpha()函数可以检测字符串是否都是字母,如果都是字母则返回True,否则返回False.

isdigit()函数可以检测字符串是否都是数字,如果是则返回True,否则返回False.

isalnum()函数检测字符串是否由字母和数字组成.

isspace()函数检测字符串是否全是空格.

1.14.5.11 使用count()函数

使用count(str)可以统计字符串str出现的次数。

 

 

 

 

1.15 列表

除了之前咱们学过的基本数据类型:bool类型、整型、浮点型、字符串之外,我们将学习另外集中数据类型:元组和列表。

1.15.1 列表概念

列表非常适合利用顺序和位置定义某一个元素,尤其是当元素的顺序或内容经常发生改变的时候。与字符串不同,列表中元素的值是可以修改的。我们可以直接对列表中进行添加新元素、删除元素、或覆盖已有的元素。

前面学习的字符串可以用来存储一串信息,那么想一想,怎样存储咱们班所有同学的名字呢?定义100个变量,每个变量存放一个学生的姓名可行吗?有更好的办法吗?

答:列表。

列表的格式:

 namesList = ['xiaoWang','xiaoZhang','xiaoHua']

比C语言的数组强大的地方在于列表中的元素可以是不同类型的:

testList = [1, 'a']

1.15.2 列表创建

列表可以由0个或者多个元素组成。元素之间用都好分开,整个列表被方括号包裹。我们可以使用[]来创建一个列表,也可以使用list函数来创建一个空列表。

list1 = []
list2 = list()

 

1.15.3 使用[]获取元素

和字符串一样,通过偏移量可以从列表中提取对应位置的元素。

list1 = ["aaa", "bbb", "ccc", "ddd"] 

list1[0]  # 输出aaa
list1[1]  # 输出bbb
list1[2]  # 输出ccc
list1[3]  # 输出ddd

 

可以使用while循环遍历输出列表中的元素,也可以使用for循环来遍历输出列表中的元素。

 #!/usr/bin/python

 #-*-coding:utf-8-*-

 

 namelist = ["Edward", "Smith", "John", "Obama", "Polly"]

 

 #打印方式一

 print(namelist[0], end= " ")

 print(namelist[1], end= " ")

 print(namelist[2], end= " ")

 print(namelist[3], end= " ")

 print(namelist[4], end= " ")

 print()

 print("---------------")

 

 #for循环方式

 for namein namelist:

         print(name,end= " ")

 

 print()

 print("---------------")

 

 #while循环方式

 index = 0

 while index< len(namelist):

         print(namelist[index], end= " ")

         index += 1

 print()

 print("---------------")

 

使用列表修改元素:

list1 = ["aaa", "bbb", "ccc", "ddd"]
list1[0]  # 输出aaa
list1[1]  # 输出bbb
list1[2]  # 输出ccc
list1[3]  # 输出ddd
list1[1] = "mmm"

 

1.15.4 列表嵌套

类似while循环的嵌套,列表也是支持嵌套的,一个列表中的元素又是一个列表,那么这就是列表的嵌套。

schoolNames = [

['北京大学','清华大学'],

['南开大学','天津大学','天津师范大学'],

['山东大学','中国海洋大学']

  ]

 

一个学校,有3个办公室,现在有8位老师等待工位的分配,请编写程序,完成随机的分配。

 

 #!/usr/bin/python

 #-*-coding:utf-8-*-

 

 import random

 

 #创建办公室列表

 offices = [[],[],[]]

 

 #员工列表

 workers = []

 #初始化员工列表

 nameID = "ABCDEFGH"

 index = 0;

 while index< 8:

         #员工姓名

         name = "员工"

         name += nameID[index]

         #print(name)

         workers.append(name)

         index += 1

 

 #随机分配员工

 for namein workers:

         #随机产生办公室编号

         officeID = random.randint(0,2)

         #将当前员工分配到办公室中

         offices[officeID].append(name)

 

 #输出各个办公室人员列表

 for work_listin offices:

         print("当前办公室员工人数:%d"%len(work_list))

         for personin work_list:

                 print(person)

 

1.15.5 列表操作

1.15.5.1 使用append()添加元素到尾部

传统的向列表中添加元素的方法是利用append()函数将元素一个个添加到尾部。

1.15.5.2 使用extend()或+=合并列表

使用extend()可以将一个列表合并到另一个列表中,我们也可以使用+=.

1.15.5.3 使用insert()在指定位置插入元素

append()函数只能将新元素插入到列表尾部,而使用insert()可以将元素插入到列表的任意位置。指定第一个参数为0,就可以将元素插入到列表头部。如果指定的第一个参数偏移量大于列表长度,则会插入到列表最后,如同append()一样。

1.15.5.4 使用del删除指定位置元素

del是python语句,而不是列表方法,无法通过list来调用。使用del可以删除一个元素,当元素删除之后,位于它后面的元素会自动移动填补空出来的位置。

1.15.5.5 使用remove()删除指定值

如果不确定或不关心元素在列表中的位置,可以使用remove()根据指定的值来删除元素。

1.15.5.6 使用pop()获取并删除指定位置元素

使用pop()同样可以获取列表中指定位置的元素,但在获取完成之后,该元素会自动被删除。如果为pop(off)指定了偏移量,它会返回偏移量对应位置的元素。如果不指定,则默认使用-1。因此pop(0)将返回头元素,而pop()或pop(-1)则会返回列表的尾元素。

1.15.5.7 使用index()查询值位置

如果想知道等于某一个值的元素在列表中的什么位置,可以使用index()函数来查询。

1.15.5.8 使用in判断值是否存在

判断一个值是否在给定的列表中有许多方式,其中最具有python风格的就是使用In,同一个值可能出现在列表的多个位置,但只要至少出现依次,in就会返回true.

1.15.5.9 使用count()值出现次数

使用count()可以记录某一个特定值在列表中出现的次数。

1.15.5.10 使用join()转换为字符串

list = [“aaa”,”bbb”,”ccc”]

“,”.join(list)

join其实是一个string的方法,而不是列表方法。不能通过list.join(“,”)进行调用,尽管看起来更直观。

1.15.5.11 使用sort()重新排列元素

在实际引用中,经常需要将列表中的元素按值排序,而不是按照偏移量排序。Python为此提供了两个函数:

l 列表方法会对原列表进行排序,改变列表排序内容;

l 通用函数sorted()则会返回排好序的列表副本,原列表内容不变。

如果列表中的元素都是数字,它们会默认的排列成从小到大的升序。如果元素都是字符串,则会按照字符表顺序排列。

默认的排序是升序排列的,通过添加参数reverse = True可以改为降序排列。

 

1.15.5.12 使用len()获得列表长度

len()可以返回列表的长度。

 

1.16 元组

与列表类似,元组也是由任意类型元素组成的序列。与列表不同的是,元组是不可改变,这意味着一旦元组被定义,将无法再进行增加、删除或修改元素等操作。因此,元组就像一个不可改变的列表.

在许多地方元组都可以替换列表,但元组的方法函数比列表要少一些,元组没有append()、insert()等等,因为一旦创建元组便无法修改。既然列表更加灵活,那为什么不在所有地方都使用列表呢?

n 元组占用空间较小;

n 你不会意外修改元组的值;

 

aTuple = ('et',77,99.9)

Ø 访问元组:

 

Ø 修改元组:

 

说明:python中不允许修改元组的数据,包括不能删除其中的元素。

Ø 元组的内置函数count, index,index和count与字符串和列表中的用法相同:

>>> a= ('a', 'b', 'c', 'a', 'b')

>>> a.index('a', 1, 3) # 注意是左闭右开区间

Traceback (most recent call last):

  File "<stdin>", line1, in <module>

ValueError: tuple.index(x): xnot in tuple

>>> a.index('a', 1, 4)

3

>>> a.count('b')

2

>>> a.count('d')

0

 

 

 

1.17 字典

字典与列表类似,但其中元素的顺序无关紧要,因为字典中的元素不是通过偏移量0、1来访问的。取而代之,每个元素拥有与之对应的互不相同的键,需要通过键来访问元素。键通常是字符串,但它还可以是Python中其他类型,比如Bool、整型、浮点型、字符串等。

 

1.17.1 字典创建

用大括号{}将一系列以逗号隔开的键值对(key:value)包裹起来即可以进行字典的创建。最简单的字典是空字典,不包括任何的键值对。

info = {'name':'班长', 'id':100, 'sex':'f', 'address':'地球亚洲中国北京'}

print(info['name'])

print(info['address'])

 

注意:列表我们使用[],元组我们使用(),字典我们使用{}.

如果访问了一个不存在的键值,会怎么样呢?那么python解释器会报错.

>>> info['age']

Traceback (most recent call last):

  File "<stdin>", line1, in <module>

KeyError: 'age'

当我们试图去访问一个不存在的键值,又不希望python解释器给我们报这么一大堆错误,我们可以通过get方式来取值:

>>> age= info.get('age')

>>> age#'age'键不存在,所以age为None

>>> type(age)

<type'NoneType'>

>>> age= info.get('age', 18) # 若info中不存在'age'这个键,就返回默认值18

>>> age

18

如果键值不存在,则返回None,我们还可以通过get函数的第二个参数设置默认返回值。

 

1.17.2 使用[]添加或修改元素

向字典添加元素非常简单,只需要指定该元素的键并赋予相应的值即可。如果该元素的键已经存在于字典中,那么该键对应的旧值会被新值取代。如果该元素的键并未在字典中出现,则会被加入到字典。与列表不用,你不需要担心赋值过程中Python会抛出越界异常。

 

1.17.3 字典操作

1.17.3.1 使用update()合并字典

使用update()可以将一个字典的键值对赋值到另一个字典中。如果待添加的字典于待扩充的字典包含同样的键值的话,新归入的字典的值会覆盖原有的值。

1.17.3.2 使用del删除具有指定键的元素

使用del可以删除具有指定key的元素。

1.17.3.3 使用clear清除所有元素

使用clear(),或者给字典重新赋值一个空字典({})可以将字典中所有元素删除。

1.17.3.4 使用in判断是否存在

如果你希望判断某一个键是否存在于一个字典中,可以使用in.

1.17.3.5 使用[key]获取元素

这是对字典最常用进行的操作,只需要指定字典名和键即可获得对应的值。如果字典中不包含指定的键,会抛出一个异常。有两种方法可以避免这种情况的发生。

第一种是在访问钱通过In测试键是否存在;

第二种使用字典函数get()。你需要指定字典名,键值和一个可选值。如果键存在,则会得到对应的值,如果不存在,将会返回可选值,如果没有指定可选值,会得到None。

1.17.3.6 使用keys()获取所有键

使用keys()可以获得字典中所有的键。在Python2中,keys()会返回一个列表,而在Python3中返回dict_keys类型,它的键是迭代器形式。如果我们需要一个完整的列表,在Python中,我们可以手动调用list()将dict_keys转换为列表类型。

1.17.3.7 使用values()获取所有值

使用values()可以获取字典中所有值。

1.17.3.8 使用items()获取所有键值对

使用items()函数可以获取字典中所有的键值对。

1.17.4 字典遍历

l 遍历字典的key(键)

 

 

l 遍历字典的value(值)

 

l 遍历字典的项(元素)

 

l 遍历字典的key-value(键值对)

 

1.16.4 公共方法

l 运算符

运算符

Python 表达式

结果

描述

支持的数据类型

+

[1, 2] + [3, 4]

[1, 2, 3, 4]

合并

字符串、列表、元组

*

'Hi!' * 4

['Hi!','Hi!', 'Hi!', 'Hi!']

复制

字符串、列表、元组

in

3 in (1, 2, 3)

True

元素是否存在

字符串、列表、元组、字典

not in

4 not in (1, 2, 3)

True

元素是否不存在

元素是否不存在

注意:in在对字典操作时,判断的是字典的键.

#+字符串

s1 = "aaa"

s2 = "bbb"

s3 = s1 + s2

print("s3 = " + s3)

 

#+列表

s4 = [1,2,3]

s5 = [4,5,6]

s6 = s4 + s5

print("s6 = ", end = " ")

print(s6)

 

#+元祖

s7 = (1,2,3)

s8 = (4,5,6)

s9 = s7 + s8

print("s9 = ",end = " ")

print(s9)

 

#*字符串

s10 = " Hello"

s11 = s10 * 4

print("s11 = " + s11)

 

#*列表

s12 = [1,2,3]

s13 = s12 * 3

print("s13 = ", end = " ")

print(s13)

 

#×元组

s14 = (1,2,3)

s15 = s14 * 3

print("s15 = ", end = " ")

print(s15)

 

#in not in

s16 = {"name":"aaa", "age" : 25}

if "name" in s16:

print("name存在!")

 

l python内置函数

cmp(item1, item2)比较两个值(3.x废弃)

len(item)计算容器中元素个数

max(item)返回容器中元素最大值

min(item)返回容器中元素最小值

del(item)删除变量

1.18 练习作业

1. 编程实现对一个元素全为数字的列表,求最大值、最小值

2. 编写程序,完成以下要求:统计字符串中,各个字符的个数

比如:"hello world" 字符串统计的结果为: h:1 e:1 l:3 o:2 d:1 r:1 w:1

3. 编写程序,完成以下要求:完成一个路径的组装

先提示用户多次输入路径,最后显示一个完成的路径,比如/home/python/ftp/share

4. 编写程序,完成“名片管理器”项目

需要完成的基本功能:

添加名片

删除名片

修改名片

查询名片

退出系统

程序运行后,除非选择退出系统,否则重复执行功能

1.17 文件

1.17.1 文件概念

一个运行的程序会存取放在内存中的数据,内存读取速度快,但是价格昂贵,需要持续供电,断电后保存在上面的数据会自动消失。磁盘速度比内存慢,但容量大、费用低廉并且多次插拔电源线仍可保存数据。因此,程序员需要在磁盘上左持久化存储。

 

 

 

文件就是把一些数据存储存放起来,可以让程序下一次执行的时候直接使用,而不必重新制作一份,省时省力。

1.17.2 文件操作

1.17.2.1 文件打开和关闭

想一想:如果想用word编写一份简历,应该有哪些流程呢?

1. 打开word软件,新建一个word文件;

2. 写入个人简历信息;

3. 保存文件;

4. 关闭word软件。

 

同样,在操作文件的整体过程与使用word编写一份简历的过程是很相似的

1.  打开文件,或者新建立一个文件;

2.  读/写数据;

3.  关闭文件;

 

那么如何打开一个文件呢?

在python,使用open函数,可以打开一个已经存在的文件,或者创建一个新文件

open(文件名,访问模式)。

 f = open('test.txt', 'w')

文件打开模式:

访问模式

说明

r

以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。

w

打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。

a

打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。

rb

以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。

wb

以二进制格式打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。

ab

以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。

r+

打开一个文件用于读写。文件指针将会放在文件的开头。

w+

打开一个文件用于读写。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。

a+

打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。

rb+

以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。

wb+

以二进制格式打开一个文件用于读写。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。

ab+

以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。

那么如何关闭一个文件呢?

# 新建一个文件,文件名为:test.txt

f1= open('test.txt', 'w')

 

# 关闭这个文件

f.close()

1.17.2.2 文件读操作

我们想要读一些文件,那么可以使用read()函数、readline()函数、或者readlines()函数。

其中read()函数可以一次性读取文件中所有的内容,也可以设置read(100),也就是一次读取100字节内容。读到文件结尾之后,再次调用read()会返回空(’’)字符串。

readline()一次可以读取一行数据。当文件读取结束后,同样也会返回空字符串。我们if not line:判断也会返回False.

函数readlines()调用的时候读取所有行,并返回单行字符串的列表。

 

读文件:

#打开文件

f = open("./index.cpp","r")

 

#1. 读取文件中所有数据

contents = f.read()

print("文件数据如下:")

#使用strip函数,删除内容中的空行

print(contents.strip())

 

#2. 指定读取5个字节

contents = f.read(5)

print(contents)

#读取剩下内容

contents = f.read()

print(contents)

 

#3. 读取一行数据

line = f.readline()

print(line,end="")

line = f.readline()

print(line,end="")

 

#4. 读取所有行

lines = f.readlines()

for linein lines:

       #判断当前行是否为空行

       if line.isspace():

               continue

       print(line,end="")

 

#关闭文件

f.close()

 

1.17.2.3 文件写操作

如果我们向文件中写入数据的话,我们可以使用write()函数。

写文件:

#打开文件

f = open("./index.cpp","w")

#1. 写入数据

contents = "hello world!"

f.write(contents)

#关闭文件

f.close()

 

1.17.2.4 文件定位读写

什么是定位?

 

 

函数名

含义

f.tell()

返回文件当前位置

f.seek(off,from)

设置位置为from位置偏移off的位置

from可选为:0文件开始 1当前位置 2文件末尾位置

 

#coding=utf-8

 

#打开文件

f = open("./test.txt","rb")

 

#输出文件当前位置

print(f.tell())

 

#当我读了两字节之后

f.read(2)

 

#输出结果为2

print(f.tell())

 

#将文件位置设置到第5个位置

f.seek(5,0)

print(f.read())

 

#将文件位置设置到文件倒数三个字符位置

#在py3中,如果不是以b模式打开文件,只允许从开始位置设置位置

#不允许从末尾偏移0-文件头,默认值;1-当前位置;2-文件尾

f.seek(-3,2)

contents = f.read()

print(chr(contents[0]))

print(contents)

 

#关闭文件

f.close()

1.17.2.5 目录操作

我们如果想通过程序去修改文件的名字、删除文件或文件夹、获得路径下的文件列表等等操作,python提供了有关这些操作的模块(os模块),需要导入模块inport os.

Ø 修改文件名字,删除文件:

Ø 目录相关操作:

函数名

描述

os.mkdir(dirname)

创建文件夹

os.getcwd()

获得当前工作目录

os.chdir(“./”)

改变至指定工作目录

os.listdir(“./”)

获得指定目录下文件列表

os.rmdir(“./”)

删除指定目录

os.rename(oldname,newname)

更改文件名

 

import os

# 创建文件夹

os.mkdir("myfile")

# 删除文件夹

os.rmdir("myfile")

# 切换工作目录

os.chdir("/")

# 显示目录下所有的文件

print(os.listdir())

 

1.17.3 文件操作案例

1.17.3.1 制作文件的备份

import os

# 输入要备份的文件

fileName = input("请输入要备份的文件:") 

# 判断目标文件是否存在

if not os.path.isfile(fileName):

    print("文件路径无效!")

else:

    # 获得文件后缀

    suffixPosition = fileName.rfind(".") 

    # 获得文件路径

    newFileName = ""

    if suffixPosition > 0:

        newFileName = fileName[:suffixPosition] + "_backup" + fileName[suffixPosition:]

    else:

        newFileName = fileName + "_backup"

 

    # 创建新文件

    newFile = open(newFileName, "wb")

    # 将待备份文件内容一行一行拷贝新文件中

    oldFile = open(fileName, "rb")

    contents = oldFile.readlines()

    newFile.writelines(contents)

 

    # 关闭两个文件

    newFile.close()

    oldFile.close()

 

    print("备份完毕!")

 

1.17.3.2 批量修改文件名

import os

 

filePath = "./folder/"

fileList = os.listdir(filePath)

print(fileList)

 

for name in fileList:

    newName = "New_" + name

    os.rename(filePath + name, filePath + newName)

 

1.17.3.3 学生管理系统

# 学生管理系统v1.0

# 添加学生信息

# 删除学生信息

# 查看学生信息

# 修改学生信息

 

# 使用字典存储学生信息

students = {}

# 学号

ID = 1000

# 退出学生管理系统

flag = True

 

def add_student():

    # 添加学生信息

    global students

    global ID

    student = {}

    # 获得学生名字

    name = input("请输入学生姓名:")

    # 获得学生成绩

    score = input("请输入学生成绩:")

    # 学号

    ID += 1

    # 保存学生成绩

    student["name"] = name

    student["score"] = score

    # 将学生信息保存到学生列表中

    students[ID] = student

    print("新学生信息添加成功!")

 

 

def del_student():

    global students

    delete_id = int(input("请输入要删除的学生ID:"))

    if delete_id in students.keys():

        # 删除学生信息

        del students[delete_id]

        # 删除成功提示

        print("学号为%d的学生信息删除成功!" % delete_id)

    else:

        print("删除的学生ID不存在!")

 

 

def show_students():

    # 打印学生信息

    for key, student in students.items():

        print("学号:%d \t姓名:%s \t分数:%s" % (key, student["name"], student["score"]))

    print("------------")

 

 

def save_students():

    # 保存学生信息到文件

    stu_info = []

    # 创建并打开文件

    stus_file = open("students.txt", "w")

    for key, student in students.items():

        stu_info.append(str(key))

        stu_info.append(student["name"])

        stu_info.append(student["score"])

        stu_data = ",".join(stu_info)

        # 给数据尾部增加换行

        stu_data += "\n"

        # 清空stu_info列表

        stu_info.clear()

        # 将学生信息写入文件中

        stus_file.write(stu_data)

 

 

def load_students():

    # 程序启动从文件中加载学生数据

    stus_file = open("students.txt", "r")  # 打开文件

    # 从文件中读取学生数据

    students_data = stus_file.readlines()

    # 声明全局变量students

    global students

    global ID

    max_id = 0

    for student in students_data:

        # 去除尾部回车

        student = student[:-1]

        stu_info = student.split(",")

        # 创建学生信息

        stu_data = {}

        stu_data["name"] = stu_info[1]

        stu_data["score"] = stu_info[2]

        # 将学生信息插入到stuents字典中

        students[int(stu_info[0])] = stu_data

        # 获得最大ID值

        if int(stu_info[0]) > max_id:

            max_id = int(stu_info[0])

 

    ID = max_id

 

 

 

def show_operations():

    print("请选择您的操作:")

    print("1. 添加学生信息")

    print("2. 删除学生信息")

    print("3. 显示学生信息")

    print("4. 退出学生系统")

    print("--------------")

 

 

def test():

    print("欢迎使用学生管理系统v1.0")

    global flag

 

    # 加载学生信息

    load_students()

    while flag:

        # 显示菜单

        show_operations()

        operation = input("您输入的操作是:")

        if operation == "1":

            add_student()

        elif operation == "2":

            del_student()

        elif operation == "3":

            show_students()

        elif operation == "4":

            flag = False

            save_students()

        else:

            print("操作错误,请重新选择操作!")

 

 

test()

 

 

1.17.6 练习作业

1. 读取一个文件,显示除了以井号(#)开头的行以外的所有行

2. 制作一个"密码薄",其可以存储一个网址(例如www.itcast.cn),和一个密码(例如123456),请编写程序完成这个“密码薄”的增删改查功能,并且实现文件存储功能

1.18 面向对象

目标:

l 面向对象概念

l 面向对象 和面向过程

1.18.1  面向对象概念

面向对象(Object Oriented,OO)是软件开发方法,是一种思想。面向对象的对象是指客观世界存在的事物。

我们之前编程所熟悉的思路叫做面向过程,我们之前在编码的时候完成一个小案例、一件事情是按照一定的顺序,从头到尾一步一步的做下去,先做什么,再做什么,一直到事情结束。这种思路比较好理解,也是我们在做一件事的时候的思路。

而面向对象则是将一个项目、或者一件事分解称一个个更小的部分,每一部分负责什么方面的功能,然后再将这些部分组合在一起合成一个整体,从而解决问题。

这两种都是比较常用的方法,都能达到通过计算机解决问题的目的。

 

思考: 设计 五子棋游戏 的 编程思路:

 

按照业务逻辑 编写五子棋程序,过程应该是这样的:

1.先显示棋盘()

2.执黑棋手下子()

3.接着刷新界面()

4.然后判断黑子是否胜出()

5.执白棋手下子()

6.接着刷新界面()

7.然后判断白子是否胜出()

8.重复2-7

对于大型程序,其逻辑和功能都很复杂,如果 按照业务逻辑 去想,我们往往无从下手。

换一个方式,想一想 五子棋游戏 中有哪些元素? 这些元素 都做了什么?

1. 根据 数据和操作 抽象出对象: 棋手 棋盘 计算系统

2. 各对象实现自己的功能: 棋手.下子 棋盘.刷新界面 计算系统.判断胜负 ..

3. 使用对象执行操作 来完成业务逻辑:

  棋盘.刷新界面

  棋手.下子

  计算系统.判断胜负

  ...

按照业务逻辑 从上到下设计程序 的方式,叫做面向过程编程 (Procedure Oriented Programming,POP,面向过程程序设计)

面向过程编程 最易被初学者接受,其往往用一长段代码来实现指定功能,一步接一步,环环相扣

对于大型项目,如果使用面向过程编程,则很容易导致 代码结构过于紧密、耦合度高,易出现代码冗余,并且 不利于团队开发.

 

面向对象编程的优点:

   将数据和业务抽象为 对象,有利于程序整体结构的分析和设计,使设计思路更加清晰

   务以对象为单位,对象各自完成工作,减少了代码耦合度,有助于业务升级和代码重构.方便工作划分,有利于提高团队开发的效率.

 

 

1.18.2  类和对象

类和对象是面向对象最重要的两个概念。对象是面向对象编程的核心,在使用对象的过程中,为了将具有共同特征和行为的一组对象抽象定义,提出了另外一个新的概念——类。

什么是类呢?

类(Class)是面向对象程序设计(OOP,Object-Oriented Programming)实现信息封装的基础。类是一种用户定义类型,也称类类型。每个类包含数据说明和一组操作数据或传递消息的函数。类的实例称为对象。

类的实质是一种数据类型,类似于int、char等基本类型,不同的是它是一种复杂的数据类型。因为它的本质是类型,而不是数据,所以不存在于内存中,不能被直接操作,只有被实例化为对象时,才会变得可操作。

类是抽象的,在使用的时候通常会找到这个类的一个具体的存在,使用这个具体的存在。一个类可以找到多个对象。

 

 

类只是定义了某个事物应该是什么样,具体来讲,也就是说该事物具有那些行为和属性。它只是一种抽象的定义,并不是某个具体的事物。但是我们可以根据类来创建具有类定义的属性和行为的具体事物。

什么是对象呢?

某一个具体事物的存在 ,在现实世界中可以是看得见摸得着的。可以是直接使用的。

 

 

 

一句话:类就是创建对象的模板。

对象中包含两个组成部分:

属性: 用于记录与对象相关的数据,比如姓名,年龄,身高,肤色等

方法: 用于实现与对象相关的操作,比如吃饭,睡觉,飞行,歌唱等

 

 

 

 

 

练习:区分类和对象:

奔驰汽车 类

奔驰smart 类

张三的那辆奔驰smart 对象

狗 类

大黄狗 类

李四家那只大黄狗 对象

水果 类

苹果 类

红苹果 类 红富士苹果 类

我嘴里吃了一半的苹果 对象

 

1.18.3  类的构成

类(Class) 由3个部分构成:

类的名称:类名;

类的属性:一组数据;

类的方法:允许对进行操作的方法 (行为)

 

栗子1,人类的设计:

人类的设计我们只关心三样东西:

l 事物名称(类名):人(Person)

l 属性:身高(height)、年龄(age)

l 方法(行为/功能):跑(run)、打架(fight)

 

栗子2,狗类的设计:

l 类名:狗(Dog)

l 属性:品种 、毛色、性别、名字、 腿儿的数量

l 方法(行为/功能):叫 、跑、咬人、吃、摇尾巴

 

1.18.4  类的抽象

如何把日常生活中的事物抽象成程序中的类?拥有相同(或者类似)属性和行为的对象都可以抽像出一个类。

方法:一般名词都是类(名词提炼法)

栗子1:坦克发射3颗炮弹轰掉了2架飞机

l 坦克-->可以抽象成类

l 炮弹-->可以抽象成类

l 飞机-->可以抽象成类

 

 

栗子2:小明在公车上牵着一条叼着热狗的狗

l 小明-->人类

l 公车-->交通工具类

l 热狗-->食物类

l 狗-->狗类

 

栗子3:想一想,如下图中,有哪些类呢?

 

 

人,枪,子弹,手榴弹,刀子,箱子

 

 

 

 

栗子4:想一想,如下图中,有哪些类呢?

 

 

向日葵:  类名: xrk

属性:

行为: 放阳光

豌豆:    类名: wd

属性: 颜色 、发型,血量

行为:发炮, 摇头

坚果:     类名:jg

属性:血量 类型

行为:阻挡;

僵尸:      类名:js

属性:颜色、血量、 类型、速度

行为:走 跑跳 吃 死

 

1.18.5  类的定义

定义类的格式:

class 类名(object):

    方法列表

 

# 定义类

class Car(object):

    # 方法

    def getCarInfo(self):

        print('车轮子个数:%d,颜色%s'%(self.wheelNum, self.color))

 

    def move(self):

        print("车正在移动...")

 

定义类时有2种:新式类和经典类,上面的Car为经典类,如果是Car(object)则为新式类

类名 的命名规则按照"大驼峰"

1.18.6  创建对象

通过上一节课程,定义了一个Car类;就好比有车一个张图纸,那么接下来就应该把图纸交给生成工人们去生成

python中,可以根据已经定义的类去创建出一个个对象

创建对象的格式为:

对象名 = 类名()

 

# 定义类

class Car:

    # 移动

    def move(self):

        print('车在奔跑...')

 

    # 鸣笛

    def toot(self):

        print("车在鸣笛...嘟嘟..")

 

 

# 创建一个对象,并用变量BMW来保存它的引用

BMW = Car()

BMW.color= '黑色'

BMW.wheelNum= 4 #轮子数量

BMW.move()

BMW.toot()

print(BMW.color)

print(BMW.wheelNum)

 

 

 

BMW = Car(),这样就产生了一个Car的实例对象,此时也可以通过实例对象BMW来访问属性或者方法。第一次使用BMW.color = '黑色'表示给BMW这个对象添加属性,如果后面再次出现BMW.color = xxx表示对属性进行修改。

BMW是一个对象,它拥有属性(数据)和方法(函数)。

当创建一个对象时,就是用一个模子,来制造一个实物 。

 

1.18.7  __init__方法

想一想:在上一小节的demo中,我们已经给BMW这个对象添加了2个属性,wheelNum(车的轮胎数量)以及color(车的颜色),试想如果再次创建一个对象的话,肯定也需要进行添加属性,显然这样做很费事,那么有没有办法能够在创建对象的时候,就顺便把车这个对象的属性给设置呢?

:__init__()方法

使用方式:

def 类名:

    #初始化函数,用来完成一些默认的设定

    def __init__():

        pass

 

__init__()方法的调用:

# 定义汽车类

class Car:

 

    def __init__(self):

        self.wheelNum= 4

        self.color= '蓝色'

 

    def move(self):

        print('车在跑,目标:夏威夷')

 

# 创建对象

BMW = Car()

 

print('车的颜色为:%s'%BMW.color)

print('车轮胎数量为:%d'%BMW.wheelNum)

 

总结1:当创建Car对象后,在没有调用__init__()方法的前提下,BMW就默认拥有了2个属性wheelNum和color,原因是__init__()方法是在创建对象后,就立刻被默认调用了。

 

想一想既然在创建完对象后__init__()方法已经被默认的执行了,那么能否让对象在调用__init__()方法的时候传递一些参数呢?如果可以,那怎样传递呢?

# 定义汽车类

class Car:

 

    def __init__(self, newWheelNum, newColor):

        self.wheelNum= newWheelNum

        self.color= newColor

 

    def move(self):

        print('车在跑,目标:夏威夷')

 

# 创建对象

BMW = Car(4, 'green')

 

print('车的颜色为:%s'%BMW.color)

print('车轮子数量为:%d'%BMW.wheelNum)

 

总结2

l __init__()方法,在创建一个对象时默认被调用,不需要手动调用;

l __init__(self)中,默认有1个参数名字为self,如果在创建对象时传递了2个实参,那么__init__(self)中出了self作为第一个形参外还需要2个形参,例如__init__(self,x,y);

l __init__(self)中的self参数,不需要开发者传递,python解释器会自动把当前的对象引用传递进去。

 

练习,创建多个对象:

l 根据上两节创建一个Car类;

l 创建出多个汽车对象,比如BMW、AUDI等;

 

1.18.8  __str__

1. 打印id():

如果把BMW使用print进行输出的话,会看到如下的信息:

 

即看到的是创建出来的BMW对象在内存中的地址.

2. 定义__str__()方法:

class Car:

 

    def __init__(self, newWheelNum, newColor):

        self.wheelNum= newWheelNum

        self.color= newColor

 

    def __str__(self):

        msg = "嘿。。。我的颜色是" + self.color+ "我有" + int(self.wheelNum) + "个轮胎..."

        return msg

 

    def move(self):

        print('车在跑,目标:夏威夷')

 

 

BMW = Car(4, "白色")

print(BMW)

 

总结:在python中方法名如果是__xxxx__()的,那么就有特殊的功能,因此叫做“魔法”方法。当使用print输出对象的时候,只要自己定义了__str__(self)方法,那么就会打印从在这个方法中return的数据。

 

1.18.9  self

# 定义一个类

class Animal:

 

    # 方法

    def __init__(self, name):

        self.name= name

 

    def printName(self):

        print('名字为:%s'%self.name)

 

# 定义一个函数

def myPrint(animal):

    animal.printName()

 

 

dog1 = Animal('西西')

myPrint(dog1)

 

dog2 = Animal('北北')

myPrint(dog2)

 

运行结果:

 

总结:

l 所谓的self,可以理解为自己

l 可以把self当做C++中类里面的this指针一样理解,就是对象自身的意思

l 某个对象调用其方法时,python解释器会把这个对象作为第一个参数传递给self,所以开发者只需要传递后面的参数即可

 

 

 

1.18.10 保护对象数据

可能你已经意识到,查看过着修改对象的属性(数据),有2种方法。

l 直接通过对象名修改

l 通过方法间接修改

明明可以使用第1种方法直接修改,为什么还要定义方法来间接修改呢?

至少有2个原因:

如果直接修改属性,烤地瓜至少需要修改2部分,即修改cookedLevel和cookedString。而使用方法来修改时,只需要调用一次即可完成。

如果直接访问属性,可能会出现一些数据设置错误的情况产生例如cookedLevel = -3。这会使地瓜比以前还生,当然了这也没有任何意义,通过使用方法来进行修改,就可以在方法中进行数据合法性的检查。

Python中没有像C++中public和private这些关键字来区别公有属性和私有属性。它是以属性命名方式来区分,如果在属性名前面加了2个下划线'__',则表明该属性是私有属性,否则为公有属性(方法也是一样,方法名前面加了2个下划线的话表示该方法是私有的,否则为公有的)。

class Plane(object):

def __init__(self):

self.mA= 100

self.mB= 200

self.__mC= 300

 

p  = Plane()

#访问失败,不可直接访问私有成员

print(p.__mC)

 

1.18.11 案例一:烤地瓜

为了更好的理解面向对象编程,下面以“烤地瓜”为案例,进行分析。

1. 分析“烤地瓜”的属性:

 

l cookedLevel : 这是数字;0~3表示还是生的,超过3表示半生不熟,超过5表示已经烤好了,超过8表示已经烤成木炭了!我们的地瓜开始时时生的。

l cookedString : 这是字符串;描述地瓜的生熟程度。

l condiments : 这是地瓜的配料列表,比如番茄酱、芥末酱等。

 

2. 分析“烤地瓜”的方法:

 

l cook(time) : 把地瓜烤一段时间

l addCondiments() : 给地瓜添加配料

l __init__() : 设置默认的属性

l __str__() : 让print的结果看起来更好一些

 

3. 分定义类,并且定义__init__()方法:

 

#定义`地瓜`类

class SweetPotato:

    '这是烤地瓜的类'

 

    #定义初始化方法

    def __init__(self):

        self.cookedLevel= 0

        self.cookedString= "生的"

        self.condiments= []

 

4. 添加"烤地瓜"方法:

 

#烤地瓜方法

def cook(self, time):

self.cookedLevel+= time

if self.cookedLevel> 8:

self.cookedString= "烤成灰了"

elif self.cookedLevel> 5:

self.cookedString= "烤好了"    

elif self.cookedLevel> 3:

self.cookedString= "半生不熟"

else:

self.cookedString= "生的"

 

5. 定义addCondiments()方法和__str__()方法

 

def __str__(self):

msg = self.cookedString+ "地瓜"

if len(self.condiments) > 0:

msg = msg+ "("

for tempin self.condiments:

msg = msg+ temp+ ", "

msg = msg.strip(", ")

 

msg = msg+ ")"

return msg

 

def addCondiments(self, condiments):

self.condiments.append(condiments)

 

6. 测试

 

class SweetPotato:

    "这是烤地瓜的类"

 

    #定义初始化方法

    def __init__(self):

        self.cookedLevel= 0

        self.cookedString= "生的"

        self.condiments= []

 

    #定制print时的显示内容

    def __str__(self):

        msg = self.cookedString+ "地瓜"

        if len(self.condiments) > 0:

            msg = msg+ "("

 

            for tempin self.condiments:

                msg = msg+ temp+ ", "

            msg = msg.strip(", ")

 

            msg = msg+ ")"

        return msg

 

    #烤地瓜方法

    def cook(self, time):

        self.cookedLevel+= time

        if self.cookedLevel> 8:

            self.cookedString= "烤成灰了"

        elif self.cookedLevel> 5:

            self.cookedString= "烤好了"    

        elif self.cookedLevel> 3:

            self.cookedString= "半生不熟"

        else:

            self.cookedString= "生的"

 

    #添加配料

    def addCondiments(self, condiments):

        self.condiments.append(condiments)

 

# 用来进行测试

mySweetPotato = SweetPotato()

print("------有了一个地瓜,还没有烤-----")

print(mySweetPotato.cookedLevel)

print(mySweetPotato.cookedString)

print(mySweetPotato.condiments)

print("------接下来要进行烤地瓜了-----")

print("------地瓜经烤了4分钟-----")

mySweetPotato.cook(4) #烤4分钟

print(mySweetPotato)

print("------地瓜又经烤了3分钟-----")

mySweetPotato.cook(3) #又烤了3分钟

print(mySweetPotato)

print("------接下来要添加配料-番茄酱------")

mySweetPotato.addCondiments("番茄酱")

print(mySweetPotato)

print("------地瓜又经烤了5分钟-----")

mySweetPotato.cook(5) #又烤了5分钟

print(mySweetPotato)

print("------接下来要添加配料-芥末酱------")

mySweetPotato.addCondiments("芥末酱")

print(mySweetPotato)

 

 

1.18.12 案例二:英雄打怪

#英雄类

class Hero(object):

def __init__(self,name):

self.mName= name

self.mAttack= 10

self.mDefense= 5

self.mHP= 100

#装备武器

self.mWeapon= None

 

#攻击函数

def attack(self,monster):

hp = self.mAttack- monster.mDefense

if hp< 0:

hp = 1

monster.mHP= monster.mHP- hp

print("英雄(%s)攻击了怪物(%s)%d滴血!"%(self.mName,monster.mName,hp))

 

#装备武器

def equipWeapon(self,weapon):

print("英雄(%s)装备了武器(%s)!"%(self.mName,weapon.mName))

print("攻击力:%d + %d"%(self.mAttack, weapon.mAttact))

self.mWeapon= weapon

self.mAttack= self.mAttack+ weapon.mAttact

 

 

#武器类

class Weapon(object):

def __init__(self,name):

self.mAttact= 20

self.mName= name

 

#怪物类

class Monster(object):

def __init__(self, name):

self.mName= name

self.mAttack= 10

self.mDefense= 20

self.mHP= 100

 

# 攻击函数

def attack(self, hero):

hp = self.mAttack- hero.mDefense

if hp< 0:

hp = 1

hero.mHP= hero.mHP- hp

print("怪物(%s)攻击了英雄(%s)%d滴血!"%(self.mName,hero.mName,hp))

 

 

 

#测试

def test():

#创建怪物

monster = Monster("黑山老妖")

#创建英雄

hero = Hero("德玛西亚")

#创建武器

weapon = Weapon("屠龙刀")

#英雄装备武器

hero.equipWeapon(weapon)

 

while True:

#英雄攻击怪物

hero.attack(monster)

if monster.mHP<= 0:

print("怪物(%s)被干死了,游戏结束!"%(monster.mName))

break

#怪物攻击英雄

monster.attack(hero)

if hero.mHP<= 0:

print("英雄(%s)被干死了,再接再厉!"%(hero.mName))

break

 

ret = input("输入任意键,继续下一个回合!")

print(ret)

 

test()

 

 

1.18.13 案例三:点和圆的关系

 

 

import math

#点类

class Point(object):

def __init__(self,x,y):

self.__mX= x

self.__mY= y

 

def setX(self,x):

self.__mX= x

 

def setY(self,y):

self.__mY= y

 

def getX(self):

return self.__mX

 

def getY(self):

return self.__mY

 

#圆类

class Circle(object):

def __init__(self,x,y,r):

#设置圆心

self.__mHeart= Point(x,y)

#设置半径

self.__mR= r

 

def setHeart(self,x,y):

self.__mHeart.setX(x)

self.__mHeart.setY(y)

 

def setR(self,r):

self.__mR= r

 

#判断点和圆之间的关系

def pointAndCircle(self,point):

a = math.pow(point.getX() - self.__mHeart.getX(),2) + math.pow(point.getY() - self.__mHeart.getY(),2)

b = math.pow(self.__mR, 2)

 

if a> b:

print("点在圆外!")

elif a< b:

print("点在圆内!")

else:

print("点在圆上!")

 

 

point = Point(10,10)

circle = Circle(10,20,100)

circle.pointAndCircle(point)

1.18.14 __del__方法

创建对象后,python解释器默认调用__init__()方法。当删除一个对象时,python解释器也会默认调用一个方法,这个方法为__del__()方法。在python中,对于开发者来说很少会直接销毁对象(如果需要,应该使用del关键字销毁)。Python的内存管理机制能够很好的胜任这份工作。也就是说,不管是手动调用del还是由python自动回收都会触发__del__方法执行:

import time

class Animal(object):

 

    # 初始化方法

    # 创建完对象后会自动被调用

    def __init__(self, name):

        print('__init__方法被调用')

        self.__name= name

 

 

    # 析构方法

    # 当对象被删除时,会自动被调用

    def __del__(self):

        print("__del__方法被调用")

        print("%s对象马上被干掉了..."%self.__name)

 

# 创建对象

dog = Animal("哈皮狗")

 

# 删除对象

del dog

 

 

cat = Animal("波斯猫")

cat2 = cat

cat3 = cat

 

print("---马上 删除cat对象")

del cat

print("---马上 删除cat2对象")

del cat2

print("---马上 删除cat3对象")

del cat3

 

print("程序2秒钟后结束")

time.sleep(2)

 

 

 

 

1.18.15 继承

1.18.15.1 单继承

在现实生活中,继承一般指的是子女继承父辈的财产,如下图:

 

在程序中,继承描述的是事物之间的所属关系,例如猫和狗都属于动物,程序中便可以描述为猫和狗继承自动物;同理,波斯猫和巴厘猫都继承自猫,而沙皮狗和斑点狗都继承足够,如下如所示:

 

 

 

那么我们为什么需要继承呢?

继承是面向对象的重要特征之一,继承是两个类或者多个类之间的父子关系,子进程继承了父进程的所有公有实例变量和方法。继承实现了代码的重用。重用已经存在的数据和行为,减少代码的重新编写。从子类角度来讲,子类可以扩展父类的行为,扩展父类的功能。

看下面的案例,比如我们像要编写一个网站,网站只有三个页面,首页,新闻页,产品展示页,我们可能进行如下实现:

 

#首页

class IndexPage(object):

    #头部信息

    def header(self):

        print("头部信息!")

 

    #底部信息

    def footer(self):

        print("底部信息!")

 

    #主体部分

    def body(self):

        print("首页主体部分内容")

 

#新闻页

class NewsPage(object):

    #头部信息

    def header(self):

        print("头部信息!")

 

    #底部信息

    def footer(self):

        print("底部信息!")

 

    #主体部分

    def body(self):

        print("新闻页主体部分内容")

 

 

#产品页

class ProductPage(object):

    #头部信息

    def header(self):

        print("头部信息!")

 

    #底部信息

    def footer(self):

        print("底部信息!")

 

    #主体部分

    def body(self):

        print("产品页主体部分内容")

 

 

#显示首页

index = IndexPage()

index.header()

index.body()

index.footer()

print("-------------")

#显示新闻页

news = NewsPage()

news.header()

news.body()

news.footer()

print("-------------")

#显示产品展示页

product = ProductPage()

product.header()

product.body()

product.footer()

以上实现,我们可以发现,三个页面,除了主体部分不同之外,那么头部和底部信息是完全一致的,但是三个页面我们需要写上相同的代码,当我的头部和底部发生改变的时候,那么就需要每个页面都要更改,维护量和维护难度就增加不少。假如网站有10000个页面,那么这个维护量是灾难性的重复劳动。如何解决呢?我们可以将公共部分剥离出去,单独写一个类,让其他页面继承这个公共页面。

#公共部分

class CommonPage(object):

    #头部信息

    def header(self):

        print("头部信息!")

 

    #底部信息

    def footer(self):

        print("底部信息!")

 

#首页

class IndexPage(CommonPage):

    #主体部分

    def body(self):

        print("首页主体部分内容")

 

#新闻页

class NewsPage(CommonPage):

    #主体部分

    def body(self):

        print("新闻页主体部分内容")

 

 

#产品页

class ProductPage(CommonPage):

    #主体部分

    def body(self):

        print("产品页主体部分内容")

 

 

#显示首页

index = IndexPage()

index.header()

index.body()

index.footer()

print("-------------")

#显示新闻页

news = NewsPage()

news.header()

news.body()

news.footer()

print("-------------")

#显示产品展示页

product = ProductPage()

product.header()

product.body()

product.footer()

 

再看下案例:

# 定义一个父类,如下:

class Cat(object):

 

    def __init__(self, name, color="白色"):

        self.name= name

        self.color= color

 

    def run(self):

        print("%s--在跑"%self.name)

 

 

# 定义一个子类,继承Cat类如下:

class Bosi(Cat):

 

    def setNewName(self, newName):

        self.name= newName

 

    def eat(self):

        print("%s--在吃"%self.name)

 

 

bs = Bosi("印度猫")

print('bs的名字为:%s'%bs.name)

print('bs的颜色为:%s'%bs.color)

bs.eat()

bs.setNewName('波斯')

bs.run()

 

说明:虽然子类没有定义__init__方法,但是父类有,所以在子类继承父类的时候这个方法就被继承了,所以只要创建Bosi的对象,就默认执行了那个继承过来的__init__方法。

总结

子类在继承的时候,在定义类时,小括号()中为父类的名字

父类的属性、方法,会被继承给子类

 

注意点:

class Animal(object):

 

    def __init__(self, name='动物', color='白色'):

        self.__name= name

        self.color= color

 

    def __test(self):

        print(self.__name)

        print(self.color)

 

    def test(self):

        print(self.__name)

        print(self.color)

 

class Dog(Animal):

    def dogTest1(self):

        #print(self.__name) #不能访问到父类的私有属性

        print(self.color)

 

 

    def dogTest2(self):

        #self.__test() #不能访问父类中的私有方法

        self.test()

 

A = Animal()

#print(A.__name) #程序出现异常,不能访问私有属性

print(A.color)

#A.__test() #程序出现异常,不能访问私有方法

A.test()

 

print("------分割线-----")

 

D = Dog(name= "小花狗", color= "黄色")

D.dogTest1()

D.dogTest2()

私有的属性,不能通过对象直接访问,但是可以通过方法访问;

私有的方法,不能通过对象直接访问;

私有的属性、方法,不会被子类继承,也不能被访问;

一般情况下,私有的属性、方法都是不对外公布的,往往用来做内部的事情,起到安全的作用。

 

以上程序中,关于代码#super().__init__()的说明

这一行代码,可以调用也可以不调用,建议调用,因为__init__方法往往是用来对创建完的对象进行初始化工作,如果在子类中重写了父类的__init__方法,即意味着父类中的很多初始化工作没有做,这样就不保证程序的稳定了,所以在以后的开发中,如果重写了父类的__init__方法,最好是先调用父类的这个方法,然后再添加自己的功能。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1.18.15.2 多继承

Camel

 

 

 

Camel

 

 

从图中能够看出,所谓多继承,即子类有多个父类,并且具有它们的特征,Python中多继承的格式如下:

# 定义一个父类

class A:

    def printA(self):

        print('----A----')

 

# 定义一个父类

class B:

    def printB(self):

        print('----B----')

 

# 定义一个子类,继承自A、B

class C(A,B):

    def printC(self):

        print('----C----')

 

obj_C = C()

obj_C.printA()

obj_C.printB()

 

python中是可以多继承的,父类中的方法、属性,子类会继承。

 

想一想:

如果在上面的多继承例子中,如果父类A和父类B中,有一个同名的方法,那么通过子类去调用的时候,调用哪个?

 

#动物类

class Animal(object):

    def eat(self):

        print("Animal::eat()")

 

#羊类

class Sheep(Animal):

    def eat(self):

        print("Sheep::eat()")

 

 

#驼类

class Camel(Animal):

    def eat(self):

        print("Camel::eat()")

 

#羊驼类

class SheepCamel(Camel,Sheep):

    pass

 

 

#创建羊驼对象

sc = SheepCamel()

sc.eat()

 

#打印eat方法搜索顺序

print(SheepCamel.__mro__)

1.18.15.3 重写和调用父类方法

所谓重写,就是子类中,有一个和父类相同名字的方法,在子类中的方法会覆盖掉父类中同名的方法

class Cat(object):

    def sayHello(self):

        print("halou-----1")

 

 

class Bosi(Cat):

 

    def sayHello(self):

        print("halou-----2")

 

bosi = Bosi()

bosi.sayHello()

调用父类的方法:

class Cat(object):

    def __init__(self,name):

        self.name= name

        self.color= 'yellow'

 

 

class Bosi(Cat):

 

    def __init__(self,name):

        #调用父类的__init__方法1(python2)

        #Cat.__init__(self,name)

        #调用父类的__init__方法2

        #super(Bosi,self).__init__(name)

        #调用父类的__init__方法3

        super().__init__(name)

 

    def getName(self):

        return self.name

 

bosi = Bosi('xiaohua')

 

print(bosi.name)

print(bosi.color)

 

1.18.16 类属性和实例属性

在了解了类基本的东西之后,下面看一下python中这几个概念的区别。

先来谈一下类属性和实例属性,在前面的例子中我们接触到的就是实例属性(对象属性),顾名思义,类属性就是类对象所拥有的属性,它被所有类对象的实例对象所共有,在内存中只存在一个副本,这个和C++中类的静态成员变量有点类似。对于公有的类属性,在类外可以通过类对象和实例对象访问。

class Person(object):

 

    #类属性,归所有此类的实例共享

    #类属性也有公有权限和私有权限之分

    contry = "china"

    #私有类属性

    __param = 100

 

    def __init__(self):

        #实例属性

        self.name= "Edward"

        self.age= 22

        self.__money= 10000

 

 

person = Person()

#实例属性

person.sex= "男"

#1. 通过对象访问类属性

print(person.contry)

#2. 通过类来访问

print(Person.contry)

 

#类外不可访问私有类属性

print(person.__param)

print(Person.__param)

 

 

#实例属性属于某一个具体对象的数据,只能通过实例对象来访问

#实例属性有公有权限的实例属性和私有权限的实例属性

 

那如果我们通过某个对象去修改类属性,那么各个对象的类属性值都会改变,对吗?且看如下代码:

class Person(object):

 

    #类属性,归所有此类的实例共享

    contry = "china"

    #私有类属性

    __param = 100

 

    def __init__(self):

        #实例属性

        self.name= "Edward"

        self.age= 22

        self.__money= 10000

 

 

p1 = Person()

p2 = Person()

 

 

#通过p1

'''

p1.contry = "USA"

print("-------------------")

print(Person.contry)

print(p1.contry)

print(p2.contry)

print("-------------------")

'''

 

#发现p2的contry并没有修改,原因是因为python解释器将p1.contry = "USA"代码

#理解为给p1增加了一个实例属性contry,并不会修改类属性

 

Person.contry= "Canada"

print("-------------------")

print(Person.contry)

print(p1.contry)

print(p2.contry)

print("-------------------")

 

如果需要在类外修改类属性,必须通过类对象去引用然后进行修改。如果通过实例对象去引用,会产生一个同名的实例属性,这种方式修改的是实例属性,不会影响到类属性,并且之后如果通过实例对象去引用该名称的属性,实例属性会强制屏蔽掉类属性,即引用的是实例属性,除非删除了该实例属性。

1.18.17 类方法和静态方法

类可以有类属性,也可以有类方法,类方法主要是对类属性的封装。是类对象所拥有的方法,需要用修饰器@classmethod来标识其为类方法,对于类方法,第一个参数必须是类对象,一般以cls作为第一个参数(当然可以用其他名称的变量作为其第一个参数,但是大部分人都习惯以'cls'作为第一个参数的名字,就最好用'cls'了),能够通过实例对象和类对象去访问。

类方法:

class People(object):

 

    #类属性

    __country = 'china'

 

    def __init__(self):

        self.name= "Edward"

 

    #类方法,用classmethod来进行修饰

    @classmethod

    def getCountry(cls):

        return cls.__country

 

    # 类方法,用classmethod来进行修饰

    @classmethod

    def setCountry(cls,country):

        cls.__country= country

 

    #类方法不可使用实例属性

    #类方法只能访问类属性

    #@classmethod

    #def showPerson(cls):

    #    print(name)

 

p = People()

print(p.getCountry())    #可以用过实例对象引用

print(People.getCountry())    #可以通过类对象引用

print("----------------")

p.setCountry("USA")

print(p.getCountry())    #可以用过实例对象引用

print(People.getCountry())    #可以通过类对象引用

 

#p.showPerson()

 

静态方法:

需要通过修饰器@staticmethod来进行修饰,静态方法不需要多定义参数.

class People(object):

    country = 'china'

 

    @staticmethod

    #静态方法

    def getCountry():

        return People.country

 

#静态方法不可访问实例属性

#静态方法可以访问类属性

#通过对象可以访问静态方法

#通过类也可访问静态方法

print(People.getCountry())

person = People()

print(person.getCountry())

 

总结:

l 从类方法和实例方法以及静态方法的定义形式就可以看出来,类方法的第一个参数是类对象cls,那么通过cls引用的必定是类对象的属性和方法;

l 而实例方法的第一个参数是实例对象self,那么通过self引用的可能是类属性、也有可能是实例属性(这个需要具体分析),不过在存在相同名称的类属性和实例属性的情况下,实例属性优先级更高;

l 静态方法中不需要额外定义参数,因此在静态方法中引用类属性的话,必须通过类对象来引用.

1.18.18 __new__方法

1.18.18.1 __new__概念

__new__方法实际上在__init__方法之前执行,用于创建类的实例。然而__init__方法负责实例创建后对其进行自定义,__new__方法才是实际上创建并返回实例的方法。

__new__方法的第一个也是最重要的参数是创建实例所需的要的类(按照惯例,命名为cls)。

在大多数起概况下,__new__方法的其他参数会被完整复制到__init__方法中。参数在调用类构造函数时首先会被传递给__new__方法,然后再传递给__init__方法。

在实际应用中,大多数类无需定义__new__方法。该方法在python中的内置实现已经足够。

通常,我们希望__new__方法返回一个已经被初始化后的类的实例。在某些情况下,并不需要这么做。需要注意的是,只有在通过__new__方法返回当前类的实例时才会执行__init__方法。如果返回的不是当前类的实例,就不会调用__init__方法。

 

class MyClass(object):

    def __new__(cls,a):

        print("__new__  被调用,参数为:%d"%a)

        #在实现__new__方法的时候,应该首先调用父类的__new__方法

        #然后再开始自定义的逻辑

        #调用父类__new__方法创建实例,并返回

        return object.__new__(cls)

 

    def __init__(self,a):

        print("__init__被调用,参数为:%d"%a)

 

 

#解释器先将参数100传递给__new__方法

#如果__new__方法创建对象,那么会调用__init__方法

#这时会将参数100再传递给__init__方法

mclass = MyClass(100)

 

总结

l __new__至少要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供;

l __new__必须要有返回值,返回实例化出来的实例,这点在自己实现__new__时要特别注意,可以return父类__new__出来的实例,或者直接是object的__new__出来的实例;

l __init__有一个参数self,就是这个__new__返回的实例,__init__在__new__的基础上可以完成一些其它初始化的动作,__init__不需要返回值;

l 我们可以将类比作制造商,__new__方法就是前期的原材料购买环节,__init__方法就是在有原材料的基础上,加工,初始化商品环节。

 

 

1.18.18.2 __new__案例

举个常见的单例模式例子,我们日常使用的电脑上都有一个回收站,在整个操作系统中,回收站只能有一个实例,整个系统都使用这个唯一的实例,而且回收站自行提供自己的实例。因此回收站是单例模式的应用。

确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,单例模式是一种对象创建型模式。

#单例类

class Chairman(object):

    __instance = None

    #由于__new__返回本类型对象就会调用__init__函数

    #需要辅助变量来控制只调用一次初始化

    __first = False

    def __new__(cls,name):

        if cls.__instance== None:

            #创建对象

            cls.__instance= super().__new__(cls)

        #返回创建的对象

        return cls.__instance

 

    #初始化函数

    def __init__(self,name):

        if self.__first:

            return

        self.__first= True

        print("Singleton::__init__()被调用!")

        self.mName= name

 

    #打印名字

    def showName(self):

        print("name = %s"%(self.mName))

 

def test():

    s1 = Chairman("Edward")

    print(id(s1))

    s1.showName()

    print("------------------")

    s2 = Chairman("Smith")

    print(id(s2))

    s2.showName()

 

if __name__== "__main__":

    test()

 

1.18.19 多态

多态的概念是应用于Java和C#这一类强类型语言中,而Python崇尚“鸭子类型”。

所谓多态:定义时的类型和运行时的类型不一样,此时就成为多态

Python “鸭子类型”,鸭子类型语言中,函数/方法可以接受一个任意类型的对象作为参数返回值,只要该对象实现了代码后续用到的属性和方法就不会报错.

class F1(object):

    def show(self):

        print 'F1.show'

 

class S1(F1):

 

    def show(self):

        print 'S1.show'

 

class S2(F1):

 

    def show(self):

        print 'S2.show'

 

def Func(obj):

    print obj.show()

 

s1_obj = S1()

Func(s1_obj)

 

s2_obj = S2()

Func(s2_obj)

 

1.23 异常

1.23.1 异常介绍

异常处理就是处理程序中的错误。谓错误是指在程序运行的过程中发生的一些异常事件(如:除0溢出,数组下标越界,所要读取的文件不存在等等)。我们可以通过函数返回值的方式返回程序运行过程中的异常,例如:

def myDiv(a,b):

    if b== 0:

        return -1

    return a/ b

当b传入值为0时候,那么函数就会运行出错,当我们发现错误的时候,我们应该返回一个错误值,当调用者判断返回值为-1的时候,就知道函数调用出现异常。

但是返回值的方式有很大的缺点:

n 这两种方法最大的缺陷就是会出现不一致问题。例如有些函数返回1表示成功,返回0表示出错;而有些函数返回0表示成功,返回非0表示出错。

n 还有一个缺点就是函数的返回值只有一个,你通过函数的返回值表示错误代码,那么函数就不能返回其他的值。

n 最重要的是返回值可以忽略。

在python中提供专门用于处理程序中错误的一种机制,异常机制,异常不可以忽略,可以跨函数,在实际开发中要比返回值的方式更加有优势。

 

python标准异常

异常名称

描述

 

 

BaseException

所有异常的基类

SystemExit

解释器请求退出

KeyboardInterrupt

用户中断执行(通常是输入^C)

Exception

常规错误的基类

StopIteration

迭代器没有更多的值

GeneratorExit

生成器(generator)发生异常来通知退出

StandardError

所有的内建标准异常的基类

ArithmeticError

所有数值计算错误的基类

FloatingPointError

浮点计算错误

OverflowError

数值运算超出最大限制

ZeroDivisionError

除(或取模)零 (所有数据类型)

AssertionError

断言语句失败

AttributeError

对象没有这个属性

EOFError

没有内建输入,到达EOF 标记

EnvironmentError

操作系统错误的基类

IOError

输入/输出操作失败

OSError

操作系统错误

WindowsError

系统调用失败

ImportError

导入模块/对象失败

LookupError

无效数据查询的基类

IndexError

序列中没有此索引(index)

KeyError

映射中没有这个键

MemoryError

内存溢出错误(对于Python 解释器不是致命的)

NameError

未声明/初始化对象 (没有属性)

UnboundLocalError

访问未初始化的本地变量

ReferenceError

弱引用(Weak reference)试图访问已经垃圾回收了的对象

RuntimeError

一般的运行时错误

NotImplementedError

尚未实现的方法

SyntaxError

Python 语法错误

IndentationError

缩进错误

TabError

Tab 和空格混用

SystemError

一般的解释器系统错误

TypeError

对类型无效的操作

ValueError

传入无效的参数

UnicodeError

Unicode 相关的错误

UnicodeDecodeError

Unicode 解码时的错误

UnicodeEncodeError

Unicode 编码时错误

UnicodeTranslateError

Unicode 转换时错误

Warning

警告的基类

DeprecationWarning

关于被弃用的特征的警告

FutureWarning

关于构造将来语义会有改变的警告

OverflowWarning

旧的关于自动提升为长整型(long)的警告

PendingDeprecationWarning

关于特性将会被废弃的警告

RuntimeWarning

可疑的运行时行为(runtime behavior)的警告

SyntaxWarning

可疑的语法的警告

UserWarning

用户代码生成的警告

 

1.23.2 异常语法

语法格式如下:

try

#可能会抛出异常的代码段

except 异常类型:

#处理异常的代码

 

#python解释器试着去执行try的代码

#如果发生错误,open函数会抛出一个异常

#在此案例中,open会抛出IOError异常

try:

    f = open("test.txt","r")

#通过使用except可以捕获异常,但需要指定捕获何种异常

#在接下来的语句中编写异常处理代码

except IOError:

    print("文件打开失败!")

 

1.23.3 捕获多个异常

上例中,我们通过except捕获了IOError异常,假如说try代码块可能返回多种异常,那么如何捕获多种异常呢?

try:

    f = open("log.txt","r")

    a = 10

    b = 0

    ret = a/ b

#捕获多个类型的异常

except (IOError,ZeroDivisionError):

    print("try语句块中的代码发生了错误!")

或者:

 

try:

    f = open("log.txt","r")

    a = 10

    b = 0

    ret = a/ b

#捕获多个类型的异常

except IOError:

    print("文件打开失败!")

except ZeroDivisionError:

    print("除0错误!")

1.23.4 获取异常描述

异常本身是一个对象,所携带了关于错误的比较详细描述,如何获取异常详细描述信息呢?

try:

    f = open("log.txt","r")

    a = 10

    b = 0

    ret = a/ b

#捕获多个类型的异常

except IOErroras ex:

    print(ex)

except ZeroDivisionErroras ex:

    print(ex)

1.23.5 捕获所有异常

捕获所有异常:

try:

    f = open("log.txt","r")

    a = 10

    b = 1

    ret = a/ b

    raise NameError

#捕获多个类型的异常

except IOErroras ex:

    print(ex)

except ZeroDivisionErroras ex:

    print(ex)

except:

    print("捕获其他异常!")

1.23.6 else用法

咱们应该对else并不陌生,在if中,它的作用是当条件不满足时执行的实行;同样在try...except...中也是如此,即如果没有捕获到异常,那么就执行else中的事情。

try:

    f = open("log.txt","r")

    a = 10

    b = 1

    ret = a/ b

 

#捕获多个类型的异常

except IOErroras ex:

    print(ex)

except ZeroDivisionErroras ex:

    print(ex)

else:

    print("没有异常,真是happy!")

1.23.7 try...finally...

try...finally...语句用来表达这样的情况:在程序中,如果一个段代码必须要执行,即无论异常是否产生都要执行,那么此时就需要使用finally。 比如文件关闭,释放锁,把数据库连接返还给连接池等。

try:

    f = open("log.txt","r")

    a = 10

    b = 0

    ret = a/ b

 

#捕获多个类型的异常

except IOErroras ex:

    print(ex)

except ZeroDivisionErroras ex:

    print(ex)

else:

    print("没有异常,真是happy!")

finally:

    print("无论是否异常发生,都会执行!")

 

import time

try:

    f = open('log.txt')

    try:

        while True:

            content = f.readline()

            if len(content) == 0:

                break

            time.sleep(2)

            print(content)

    except KeyboardInterrupt:

        #如果在读取文件的过程中,产生了异常,那么就会捕获到

        #比如 按下了ctrl+c

        print("捕获到了以外终止异常!")

    finally:

        f.close()

        print('关闭文件')

except:

    print("没有这个文件")

 

test.txt文件中每一行数据打印,但是我有意在每打印一行之前用time.sleep方法暂停2秒钟。这样做的原因是让程序运行得慢一些。在程序运行的时候,按Ctrl+c中断(取消)程序。

我们可以观察到KeyboardInterrupt异常被触发,程序退出。但是在程序退出之前,finally从句仍然被执行,把文件关闭。

 

1.23.8 try嵌套

import time

try:

    f = open('log.txt')

    try:

        while True:

            content = f.readline()

            if len(content) == 0:

                break

            time.sleep(2)

            print(content)

    finally:

        f.close()

        print('关闭文件')

except:

    print("没有这个文件")

 

 

总结:

l 如果try嵌套,那么如果里面的try没有捕获到这个异常,那么外面的try会接收到这个异常,然后进行处理,如果外边的try依然没有捕获到,那么再进行传递。

l 如果一个异常是在一个函数中产生的,例如函数A---->函数B---->函数C,而异常是在函数C中产生的,那么如果函数C中没有对这个异常进行处理,那么这个异常会传递到函数B中,如果函数B有异常处理那么就会按照函数B的处理方式进行执行;如果函数B也没有异常处理,那么这个异常会继续传递,以此类推。。。如果所有的函数都没有处理,那么此时就会进行异常的默认处理,即通常见到的那样。

l 注意观察上图中,当调用test3函数时,在test1函数内部产生了异常,此异常被传递到test3函数中完成了异常处理,而当异常处理完后,并没有返回到函数test1中进行执行,而是在函数test3中继续执行。

1.23.9 自定义异常抛出

你可以用raise语句来引发一个异常。通过创建一个新的异常类,程序可以命名它们自己的异常。异常应该是典型的继承自Exception类,通过直接或间接的方式。

以下为与RuntimeError相关的实例,实例中创建了一个类,基类为RuntimeError,用于在异常触发时输出更多的信息。

在try语句块中,用户自定义的异常后执行except块语句,变量 e 是用于创建Networkerror类的实例。

下面是一个引发异常的例子:

#自定义异常类

class OutOfRangeException(Exception):

    def __init__(self,errMsg):

        self.msg= errMsg

 

    def __str__(self):

        return self.msg

 

 

class Person(object):

    def __init__(self):

        self.name= None

        self.age= None

 

    def setAge(self,age):

        if age< 0 or age> 100:

            raise  OutOfRangeException("年龄应该在0-100之间!")

        self.age= age

 

    def setName(self,name):

        self.name= name

 

    def __str__(self):

        return "name:{} age:{}".format(self.name,self.age)

 

if __name__== "__main__":

    person = Person()

    person.setName("Edward")

    person.setAge(80)

    print(person)

try:

    person.setAge(101)

except OutOfRangeExceptionas ex:

    print(ex)

 

 

1.24 模块

1.24.1 模块概念

模块就是包含了python代码的文本文件,通俗讲,一个py文件就是一个模块。在python的标准库中已经预加载了大量的模块。那么这些模块有什么用呢?何不把所有的py代码都放在一个文件中呢?

大量代码在一个文件中,不易于维护,大量的代码会让人眼花缭乱,我们根据功能不同分为多个文件,那么维护的时候就很方便了。

从另一方面,我们会写一些比较有用的代码,我们将其封装为单独的模块,下次使用此功能的时候就不需要重写编写代码,达到复用的效果,我们的程序也不需要每次都从零开始了。

封装为单独的模块,还可以解决命名冲突的问题,不同模块中的名字是可以重复的。但是同一模块中名字是不可以重复的。达到复用名字的效果。

1.24.2 使用模块(import)

比如,我们单独编写了一个模块,命名为mymodule.py,在该模块中我们定义一些函数和类,我们如何在test.py中使用呢?答案是使用import.

mymodule.py内容如下:

#Person类

class Person(object):

    def __init__(self,name,age):

        self.name= name

        self.age= age

 

    def showPerson(self):

        print("Name:%s Age:%d"%(self.name,self.age))

 

#函数

def myAdd(a,b):

    ret = a+ b

    return ret

test.py如下:

#引入mymodule模块

import mymodule

 

#使用mymodule模块中的myAdd函数

#注意在使用mymodule中的符号的时候,必须指定模块名.符号的方式

ret = mymodule.myAdd(10,20)

print("ret = %d"%ret)

 

#使用mymodule模块中的Person类

person= mymodule.Person("Edward",22)

person.showPerson()

 

不仅可以引入函数,还可以引入一些全局变量、类等.

为什么必须加上模块名调用呢?

因为可能存在这样一种情况:在多个模块中含有相同名称的函数,此时如果只是通过函数名来调用,解释器无法知道到底要调用哪个函数。所以如果像上述这样引入模块的时候,调用函数必须加上模块名.

1.24.3 使用模块(from...import...)

有时候我们只需要用到模块中的某个函数,只需要引入该函数即可.通过这种方式引入的时候,调用函数时只能给出函数名,不能给出模块名,但是当两个模块中含有相同名称函数的时候,后面一次引入会覆盖前一次引入。也就是说假如模块A中有函数function( ),在模块B中也有函数function( ),如果引入A中的function在先、B中的function在后,那么当调用function函数的时候,是去执行模块B中的function函数。如果想一次性引入math中所有的东西,还可以通过from math import *来实现

#引入mymodule模块中的myAdd函数

from mymoduleimport  myAdd

 

#使用mymodule模块中的myAdd函数

#注意不可添加模块名

ret = myAdd(10,20)

print("ret = %d"%ret)

 

#使用mymodule模块中的Person类出错

#person= mymodule.Person("Edward",22)

#person.showPerson()

使用import xxx import *

#引入mymodule模块中的所有符号

from mymoduleimport *

 

#使用mymodule模块中的myAdd函数

#注意不可添加模块名

ret = myAdd(10,20)

print("ret = %d"%ret)

 

#使用mymodule模块中的Person类出错

person= Person("Edward",22)

person.showPerson()

这提供了一个简单的方法来导入一个模块中的所有项目。然而这种声明不该被过多地使用。

 

1.24.4 使用模块(import...as...)

将引入的模块重新命名:

#引入mymodule并重新命名为md

#此时再使用mymodule就会未定义

import mymoduleas md

 

#使用mymodule模块中的myAdd函数

#注意不可添加模块名

ret = md.myAdd(10,20)

print("ret = %d"%ret)

 

#使用mymodule模块中的Person类出错

person= md.Person("Edward",22)

person.showPerson()

 

1.24.5 定位模块

当你导入一个模块,Python解析器对模块位置的搜索顺序是:

l 当前目录。

l 如果不在当前目录,Python则搜索在shell变量PYTHONPATH下的每个目录。

l 如果都找不到,Python会察看默认路径。UNIX下,默认路径一般为/usr/local/lib/python/

l 模块搜索路径存储在system模块的sys.path变量中。变量里包含当前目录,PYTHONPATH和由安装过程决定的默认目录。

1.24.6 __name__变量

#引入mymodule并重新命名为md

#此时再使用mymodule就会未定义

import mymoduleas md

 

#使用mymodule模块中的myAdd函数

#注意不可添加模块名

ret = md.myAdd(10,20)

print("ret = %d"%ret)

 

#使用mymodule模块中的Person类出错

person= md.Person("Edward",22)

person.showPerson()

 

当我们执行此py文件的时候,由于此py文件包含了mymodule.py,导致mymodule中的测试程序也被执行了.

可以根据__name__变量的结果能够判断出,是直接执行的python脚本还是被引入执行的,从而能够有选择性的执行测试代码.

1.24.7 模块中的__all__

1. 没有__all__

 

 

 

 

 

2. 有__all__

 

 

 

 

如果一个文件中有__all__变量,当使用from xxx import *时导入的时候,只能导入__all__中的符号,其余符号导入失败.

1.25 包

1.25.1 包的概念

包是一个分层次的文件目录结构,它定义了一个由模块及子包,和子包下的子包组成的Python应用环境。简单来说就是文件夹,但文件夹下必须存在__init__.py文件,该文件的内容可以为空。__init__文件用于标识当前文件夹是一个包。

为了组织好模块,将多个模块分为一个包。包是python模块文件所在的目录,且该目录下必须存在__init__.py文件。常见的包结构如下:

package_a

├── __init__.py

├── module_a1.py

└── module_a2.py

package_b

├── __init__.py

├── module_b1.py

└── module_b2.py

有2个模块功能有些联系

 

所以将其放到同一个文件夹下:

 

使用import 文件.模块 的方式导入:

 

使用from 文件夹 import 模块 的方式导入:

 

在msg文件夹下创建__init__.py文件:

 

 在__init__.py文件中写入:

 

重新使用from 文件夹 import 模块 的方式导入:

 

包将有联系的模块组织在一起,即放到同一个文件夹下,并且在这个文件夹创建一个名字为__init__.py 文件,那么这个文件夹就称之为包。

有效避免模块名称冲突问题,让应用组织结构更加清晰。

1.25.2 __init__.py

__init__.py 控制着包的导入行为。

如果__init__.py为空,那么仅仅是将包导入,不会导入包的任何模块。

在__init__.py文件中,定义一个__all__变量,它控制着 from 包名 import *时导入的模块。

可以在__init__.py文件中编写内容,可以在这个文件中编写语句,当导入时,这些语句就会被执行。

_init__.py

 

 

1.26 编码规范

l 不要在行尾加分号, 也不要用分号将两条命令放在同一行.

l 每行不超过80个字符,Python会将 圆括号, 中括号和花括号中的行隐式的连接起来 , 你可以利用这个特点. 如果需要, 你可以在表达式外围增加一对额外的圆括号.例如:

x = ('This will build a very long long '
     'long long long long long long string'
)

l 在注释中,如果必要,将长的URL放在一行上。

# See details at

#http://www.example.com/us/developer/documentation/api/content/v2.0/

l 宁缺毋滥的使用括号.除非是用于实现行连接, 否则不要在返回语句或条件语句中使用括号. 不过在元组两边使用括号是可以的.

l 用4个空格来缩进代码.绝对不要用tab, 也不要tab和空格混用.

l 顶级定义之间空两行. 方法定义之间空一行.顶级定义之间空两行, 比如函数或者类定义. 方法定义, 类定义与第一个方法之间, 都应该空一行. 函数或方法中, 某些地方要是你觉得合适, 就空一行.

l 按照标准的排版规范来使用标点两边的空格.不要在逗号, 分号, 冒号前面加空格, 但应该在它们后面加(除了在行尾). 参数列表, 索引或切片的左括号前不应加空格.在二元操作符两边都加上一个空格, 比如赋值(=), 比较(==, <, >, !=, <>, <=, >=, in, not in, is, is not), 布尔(and, or, not). 至于算术操作符两边的空格该如何使用, 需要你自己好好判断. 不过两侧务必要保持一致.当’=’用于指示关键字参数或默认参数值时, 不要在其两侧使用空格.

l 块注释和行注释.最需要写注释的是代码中那些技巧性的部分.如果你在下次 代码审查 的时候必须解释一下,那么你应该现在就给它写注释.对于复杂的操作,应该在其操作开始前写上若干行注释.对于不是一目了然的代码,应在其行尾添加注释.为了提高可读性,注释应该至少离开代码2个空格.

l 如果一个类不继承自其它类, 就显式的从object继承.嵌套类也一样.

l 每个导入应该独占一行.导入总应该放在文件顶部.例如:

Yes: import os

     import sys

No:  import os, sys

l 通常每个语句应该独占一行.

命名规范

l 所谓”内部(Internal)”表示仅模块内可用, 或者, 在类内是保护或私有的.

l 用单下划线(_)开头表示模块变量或函数是protected的(使用import * from时不会包含).

l 用双下划线(__)开头的实例变量或方法表示类内私有.

l 将相关的类和顶级函数放在同一个模块里. 不像Java, 没必要限制一个类一个模块.

l 对类名使用大写字母开头的单词(如CapWords, 即Pascal风格), 但是模块名应该用小写加下划线的方式(如lower_with_under.py). 尽管已经有很多现存的模块使用类似于CapWords.py这样的命名, 但现在已经不鼓励这样做, 因为如果模块名碰巧和类名一致, 这会让人困扰.

Python之父Guido推荐的规范

Type

Public

Internal

Modules

lower_with_under

_lower_with_under

Packages

lower_with_under

 

Classes

CapWords

_CapWords

Exceptions

CapWords

 

Functions

lower_with_under()

_lower_with_under()

Global/Class Constants

CAPS_WITH_UNDER

_CAPS_WITH_UNDER

Global/Class Variables

lower_with_under

_lower_with_under

Instance Variables

lower_with_under

_lower_with_under (protected) or __lower_with_under (private)

Method Names

lower_with_under()

_lower_with_under() (protected) or __lower_with_under() (private)

Function/Method Parameters

lower_with_under

 

Local Variables

lower_with_under

 

 

 

 

  • 25
    点赞
  • 134
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值