第五讲:函数与类库
- 第五讲:函数与类库
- 函数
- 定义
- 实参
- 变量的作用域
- 返回值
- 代码复用
- 类
- 创建和使用类
- 继承
- 导入类
- 模块与库
- 概念
- 标准库
- 第三方库
第五讲:函数与类库
函数
定义
函数就是代码块,只不过我们给这个代码块特地进行命名,固定住它以后就
用来干某个具体的工作。
当我们需要用程序多次执行同一项任务时,就会需要反复编写完成该任务的代码,这将会使我们的代码变得冗长繁杂,所以函数诞生了。我们只需要把这个需要反复编写的代码块定义为某个函数并命名,使用的时候只需要调用它的名字,即可反复执行任务。所以函数的优点是能够通过代码复用是的程序本身的编写、阅读、测试、修复和改进更加简易。
函数定义格式:
def text(id):
a = id + "真厉害!"
return print(a)
text("xqs")
text("123")
text("1234")
函数名为 text,参数为 id,函数作用为输出简单的称呼,函数体为 S = id + “真厉害!” ,返回值为 print(a) 。函数调用为text(“xqs”) text(“123”)。
实参与形参
函数text(id)要求给id指定一个值。当我们调用这个函数并给定值的时候,它就会输出感恩话语。
其实,在函数text(id)的定义中,变量id是一个形参——形式上的参数,即函数执行任务所需的一项信息。在函数调用text(“xqs”)的时候,我们向形参传递了一个实参——实际参数,即函数执行任务所拥有的一项信息——”xqs“,此时实参”xqs“被储存在形参id中。同理,函数调用text(“123”)时,实参"123"被储存在形参id中;函数调用text(“1234”)时,实参"1234"被储存在形参id中。
实参
由于函数定义中可能会含有多个形参,因此函数调用中也需要输入多个实参。向形参传递实参的方式主要有两种:位置实参和关键字实参。
- 位置参数
在调用参数函数时,必须将每个形参都赋值为每个实参。最简单的关联方式是基于形参的位置顺序传递实参,这种关联方是成为位置参数。
def thank_you(something, name):
R = "You help me with " + something + "." + name
S = "Thank you," + name
return print(R,S)
thank_you("Chinese","xqs")
thank_you("123","456")
这个函数定义为thank_you(something, name),形参顺序是something,name,正确的顺序是先"Chinese"后"xqs"。正确的实参传递是,第一个是You help me with Chinese . xqs;第二个是You help me with xqs . Chinese;
- 关键字参数
由于形参顺序太难处理,我们就可以使用关键字参数方法。关键字参数方法是传递给函数一对——“形参名称-实参”,直接将形参和实参关联起来,因此不会出现顺序混淆导致的错误结果,并且能够指出函数调用各个值的意义。
def thank_you(something, name):
R = "You help me with " + something + "." + name
S = "Thank you," + name
return print(R,S)
thank_you(something="Chinese",name="xqs")
thank_you(name="xqs",something="Chinese")
当我们指定了将 something 赋值为”Chinese”,将 name 赋值为”xqs”之后,不论顺序如何,都能够正确地输出结果。
变量的作用域
根据程序中变量所在的位置和作用域,分为局部变量和全局变量。
- 局部变量
局部变量是指在函数内部定义的变量,仅在函数内部有效。
def thank_you(something, name):
R = "You help me with " + something + "." + name
S = "Thank you," + name
return print(R,S)
thank_you(something="Chinese",name="xqs")
thank_you(name="xqs",something="Chinese")
print(R)
我们在函数外部使用函数内部变量 R 的时候,会提示 R 没有定义,即不存在。
- 全局变量
全局变量是指在函数外部定义的变量,在整个程序中有效。若要在函数内部使用全局变量,则分为两种情况:一是单纯引用,则不需要任何操作;二是需要在函数内部修改全局变量,则需要提前使用保留字 global 声明。
返回值
函数没有返回值,因此打印输出的结果为 None
函数加上了 return 返回了立方值,因此打印输出结果为 8。
代码复用
- 简单的代码复用
编写函数称为封装,执行函数称为调用,代码复用即将封装起来的函数进行调用。
def text(x):
a = x**3
print(a)
def thank_you(something, name):
R = "You help me with " + something + "." + name
S = "Thank you," + name
return print(R,S)
text(2)
thank_you(something="2的立方值",name="xqs")
text(5)
thank_you(name="xqs",something="5的立方值")
先封装两个函数,然后分别进行调用。
- 将函数储存在模块
将函数储存在模块中,再将模块导入主程序。通过将函数储存在独立文件中,可以把重点放在程序的更高层逻辑上。还能帮助我们在其他程序编写中使用此函数,还可以将此函数分享给其他程序员,同样地还可以使用其他程序员编写的函数库。
首先创建模块,模块是扩展名为.py 的文件,其中为封装好的函数。xqs.py 即为模块我们创建的摸块。
(1) 导入整个模块
当我们导入整个模块之后,那么模块包含的函数就可以使用了。
在同一个文件夹下创建了一个求立方和表示感谢的 py 文件,在这个文件中导入刚才创建的模块,再进行函数调用,可以发现这些代码运行正确。这种导入整个模块再进行函数调用的方法总结为:
(2) 导入指定函数
如果整个模块有许多函数,而我们只需要其中的一、两个函数,那么我们可以指定函数名进行特定导入。这种导入指定函数的方法总结为:
(3) 使用 as 给模块指定别名
我们的模块名为“xqs”,稍显冗长。我们可以给他指定一个缩写名,方便使用,可以得到一样的运行结果。这种以别名导入模块的方法总结为:
(4) 使用 as 给函数指定别名
我们的函数名为“thank_you”,稍显冗长。我们可以给他指定一个缩写名,方便使用。
(5) 导入模块中的所有函数
使用(*)符号可以导入模块中的所有函数,如果模块不是自己写的,由于函数名很可能会重复,所以出现一些意想不到的结果。导入模块中的所有函数的方法总结为:
综上,代码复用最为推荐以上的第(3)种方式——使用 as 给模块指定别名,这样会减少出错概率,并且使代码更为清晰、更加容易阅读和理解。
类
类就是对象的抽象式汇总,基于类创建对象的时候,每个对象都具有类的通用属性,在获得通用属性的基础上,可根据需要赋予对象以个性。
创建和使用类
- 创建类
现在创建一个表示猫咪的简单类 Cat(习惯上类的命名一般都是开头字母大写)。想象一下猫咪,能联想到的共性是两条信息(名字、胖瘦)和两种动作(舔毛、踩奶),所以我们创建的 Cat 类将包含他们。
Cat类的语法结构:
具体解释:
第 1 行,类的命名应为首字母大写,括号内是空的;
第 2 行,我们对这个类的功能进行了说明;
第 4 行,我们开始在类中编写函数,实际上除了上文中的模块,类是函数的另一种汇总方式,在类中的函数我们称为方法。
显然在这个类中有三种方法,首先是第 4 行的__ini__()方法,然后是第 9 行的舔毛()方法,再是第 13 行的踩奶()方法。其中__ini__()方法是类中特有的默认的方法,每当我们根据 Cat 类创建新实例时,Python 都会自动运行它。注意它的开头末尾各有两个下划线,这是默认约定,能够避免与我们定义的普通函数发生命名冲突。
单独对__ini__()方法进行剖析,在此方法中包含了三个形参:self、name 和身材。首先,形参 self 不可缺失且必须位于参数最前。具体原因不必深究,这么做的目的是可以理解为方便自己引用自己。再之,对于形参 self,我们不需要传递实参。最后,对于后面两个形参,每次创建 Cat 类实例时,都需要给他俩提供实参。
对于另外两个方法:舔毛()和踩奶()。由于这些方法是单独定义的,因此不需要额外的信息,因此只需要一个形参 self。在这里,舔毛()和踩奶()只是打印一条信息说明猫咪是在作出行为,但是随着学习我们可以编写一个动画真正实现。
class Cat():
def __init__(self, name, 身材):
self.name = name
self.身材 = 身材
def 舔毛(self):
print(self.name + "正在舔毛")
def 踩奶(self):
print(self.name + "正在踩奶")
- 实例化
接下来将 Cat 类实例化,即创建一个表示特定猫咪的实例,它的名字叫咪咪,身材属性是胖。
class Cat():
def __init__(self, name, 身材):
self.name = name
self.身材 = 身材
def 舔毛(self):
print(self.name + "正在舔毛")
def 踩奶(self):
print(self.name + "正在踩奶")
my_cat = Cat("咪咪","胖")
(1)访问属性
self.name 和 self.身材是 Cat 类中的属性,舔毛()和踩奶()是 Cat类中的方法。访问属性时采用句点表示法:
class Cat():
def __init__(self, name, 身材):
self.name = name
self.身材 = 身材
def 舔毛(self):
print(self.name + "正在舔毛")
def 踩奶(self):
print(self.name + "正在踩奶")
my_cat = Cat("咪咪","胖")
print("My cat's name is " + my_cat.name + ".")
print("我的小猫咪身材" + my_cat.身材 + "。")
(2)调用方法
调用方法时,也采用句点表示法:
class Cat():
def __init__(self, name, 身材):
self.name = name
self.身材 = 身材
def 舔毛(self):
print(self.name + "正在舔毛")
def 踩奶(self):
print(self.name + "正在踩奶")
my_cat = Cat("咪咪","胖")
my_cat.舔毛()
my_cat.踩奶()
(3)创建多个实例
我们可根据需求创建其他的实例,比如你也有一只猫,那我也可以把你的猫实例化。
class Cat():
def __init__(self, name, 身材):
self.name = name
self.身材 = 身材
def 舔毛(self):
print(self.name + "正在舔毛")
def 踩奶(self):
print(self.name + "正在踩奶")
my_cat = Cat("咪咪","胖")
print("My cat's name is" + my_cat.name + ".")
print("我的小猫咪身材" + my_cat.身材 + "。")
my_cat.踩奶()
your_cat = Cat("喵喵","瘦")
print("My cat's name is" + my_cat.name + ".")
print("我的小猫咪身材" + my_cat.身材 + "。")
your_cat.舔毛()
继承
- 继承父类
如果要编写的类是另一个已经编号的类的特殊版本,那么就可以使用继承。类 a 继承另一个类 A 的时候,将自动获得类 A 的所有属性和方法;原有的类 A 成为父类,新类 a 成为子类。子类除了继承其父类的所有属性和方法之外,还可以定义自己的属性和方法。
例如,模拟英短猫这个品种的猫咪,我们可以在前面创建的 Cat 类基础上创建新类 EdCat,只需要为英短猫特有的属性和行为编写代码。具体来说,EdCat 子类的创建首要完成任务是获得父类 Cat 类的属性,因此需要如下结构形式:首先是 Cat 类代码。创建子类时,父类必须包含在当前文件中,且位于子类前面。接着开始定义子类 EdCat(),括号中必须包含父类名。__init__方法中接受创建 Cat 实例所需信息,super()是一个能够将父类和子类关联的特殊函数,完成继承。
为了测试继承是否成功,创建了my_edcat英短猫my_edcat并输出其身材,发现其与猫咪信息相同,具备猫咪的属性,所以继承成功。
class Cat():
def __init__(self, name, 身材):
self.name = name
self.身材 = 身材
def 舔毛(self):
print(self.name + "正在舔毛")
def 踩奶(self):
print(self.name + "正在踩奶")
class EdCat(Cat):
def __init__ (self,name,身材):
super().__init__(name,身材)
my_edcat = EdCat("咪咪","胖")
print(my_edcat.身材)
- 子类定义新属性和方法
子类继承了父类属性之后,可添加一些子类特有的新属性和方法。
以英短猫为例,添加新属性以及一个相关联的方法。新属性为英短猫特点以及描述特点的方法。
class Cat():
def __init__(self, name, 身材):
self.name = name
self.身材 = 身材
def 舔毛(self):
print(self.name + "正在舔毛")
def 踩奶(self):
print(self.name + "正在踩奶")
class EdCat(Cat):
def __init__ (self,name,身材):
super().__init__(name,身材)
self.英短特点 = "圆脸尖耳,好奇心强,与人亲近"
def 描述_英短特点(self):
print("英短猫的特点是:" + self.英短特点 + "。")
my_edcat = EdCat("咪咪","胖")
my_edcat.描述_英短特点()
代码注释:
第 15 行是新属性,第 17 行是与新属性相关联的新方法,第 21 行是调用新方法,运行结果说明新属性和新方法定义成功。如果有需要还可以添加其他新属性与方法,来更加清晰地定义英短猫的类,Python 并无限制。
- 重写父类方法
某些父类方法可能不符合子类的特性,我们可以对其进行重写。只要在子类中定义一个与父类重名的方法,Python 在运行时将不会考虑父类方法,而直接选择子类定义的相应方法作为运行对象。
比如 Cat()类中有一个踩奶()的方法,对于英短来说,没有瘦的,都是胖圆健硕的,所以要重写方法。
class Cat():
def __init__(self, name, 身材):
self.name = name
self.身材 = 身材
def 舔毛(self):
print(self.name + "正在舔毛")
def 踩奶(self):
print(self.name + "正在踩奶")
class EdCat(Cat):
def __init__ (self,name,身材):
super().__init__(name,身材)
self.英短特点 = "圆脸尖耳,好奇心强,与人亲近"
def 描述_英短特点(self):
print("英短猫的特点是:" + self.英短特点 + "。")
def 踩奶(self):
print(self.name + "英短踩奶")
my_edcat = EdCat("咪咪","胖")
my_edcat.踩奶()
导入类
为了让代码尽可能实现这个理念,python 允许将类存储在模块中,在主程序中导入所需模块简化代码。上一小节讲了函数可以存储在模块中简化代码,这一节将讲述将类存储在模块中简化代码。
- 导入单个类
(1) 创建包含单个类的模块
首先创建一个只包含 Cat()类的模块,代码与之前的 Cat()类完全相同,区别只是我们将其存储在 cat.py 的模块中。
(2) 导入单个类
紧接着我们导入 Cat()类并将其实例化,用 from <模块名> import <类名> 语句打开模块 cat 并导入其中的 Cat()类。
PS:如果这个 my_cat.py 文件中包含了整个 Cat 类,它的长度像之前所展示的,非常之长。但是通过将类转移到模块中,编写代码时,导入该模块,就可以使用其所有功能,主程序代码将会整洁易读。从代码编写过程中的逻辑思维来讲,底层逻辑将会被储存在模块这种独立文件中,我们就能够专注于更高层的逻辑。
import cat
my_cat = cat.Cat("咪咪","胖胖")
my_cat.踩奶()
print("\n")
my_edcat = cat.EdCat("哈哈","健硕")
my_edcat.踩奶()
- 导入多个类
(1) 创建包含多个类的模块
首先创建一个包含 Cat()类和 EdCat()类的模块,既可以模拟猫,也可以模拟英短猫。代码与之前的 Cat()类和 EdCat()类完全相同,区别只是我们将其存储在cat.py 的模块中。
(2) 导入多个类
我们要在同一个程序中创建猫咪和英短猫咪,因此我们同事导入 Cat()和EdCat()两个类,导入相应的类之后,就可以根据需要创建任意数量的实例,在这个示例中,我们创建了一只叫咪咪的小猫咪和一只叫哈哈的英短猫咪。
from cat import Cat, EdCat
my_cat= Cat("咪咪","胖胖")
print("My cat's name is " + my_cat.name + ".")
print("我的小猫咪身村" + my_cat.身材 + "的。")
my_cat.踩奶()
print("\n")
my_edcat = EdCat("哈哈","健硕")
print("我的英短的名字是" + my_edcat.name + "。")
my_edcat.踩奶()
my_edcat.描述_英短特点()
- 导入整个模块
(1)导入整个模块
导入整个模块之后,使用句点表示法访问需要的类。
import cat
my_cat = cat.Cat("咪咪","胖胖")
my_cat.踩奶()
print("\n")
my_edcat = cat.EdCat("哈哈","健硕")
my_edcat.踩奶()
(2)导入模块中的所有类
与之前的导入模块中的所有函数相同,使用语法为:
这种方式不推荐,因此不列举具体示例。
不推荐的原因有两点:一是不能清除地知道程序使用了哪些类,二是有可能会出现相同命名的名称。
模块与库
概念
- 模块
模块即一组函数或者一组类,它的作用是将函数或者类成组地保存为独立文件,方便我们更专注于程序编写的更高层逻辑。 - 库
库即一组模块,它的作用是将模块成组地保存为独立文件,方便我们更专注于程序编写的更更高层逻辑。
前面 4 讲所学的普通程序语句是最底层,后面的函数和类算是平级(但是类中可以包含多个方法,类中方法即函数),类稍大一级,都归于中层,再后面的模块是高层,最后是超高层——库。
标准库
库分为标准库和第三方库,标准库是 Python 内置的,无需安装;第三方库则是由国内外大神自己开发的开源使用的库,需要安装。
- turtle 库
turtle(海龟)是一个能够进行图形绘制的库,它的绘制概念非常直观——turtle 小海龟在笛卡尔直角坐标系中爬行,其爬行轨迹形成了图形。小海龟最初位于坐标系原点(0, 0),前进方向为 X 轴正向,小海龟有有“前进”、“旋转”、“后退”等爬行操作,如,输入以下代码,“小海龟”正在向前爬 1000个像素。
import turtle
turtle.forward(1000)
下面介绍一道 Python 二级真题,让我们来看看具体如何考察?
考生文件夹下存在一个文件 PY201.py,请写代码替换横线,不修改其他代码,实现以下功能:【10 分】
使用turtle库的turt1e.right()函数和turt1e.fd()函数绘制一个正方形,
边长为 200 像素,效果如图所示。
import turtle
#方法一
d = 0
for i in range(4):
turtle.fd(200)
d += 90
turtle.seth(d)
#方法二
for i in range(1,5):
turtle.fd(200)
turtle.seth(90*i)
#方法三
for i in range(4):
turtle.fd(200)
turtle.seth(90)
turtle.fd()是前进函数,turtle.seth()函数可以改变海龟的行进方向(角度按逆时针)。方法二是一个 for 循环,不做过多解释;方法三中turtle.left()函数也可以改变海龟的行进方向(角度按逆时针)。
- random 库
Python 提供的 random 库可用于产生各种分布的伪随机数序列。在random 库中,最基本的函数random.random(),它能够胜出一个[0.0, 1.0)之间的随机小数。
下面是一道 Python 二级真题,让我们来看看具体如何考察?
考生文件夹下存在一个文件 PY103.py,请写代码替换横线,不修改其他代码,题目要求如图 5.36,实现以下功能:【5 分】
- 以 123 为随机数种子,随机生成 10 个在 1(含)到 999(含)之间的随机数,每个随机数后跟随一个逗号进行分隔,屏幕输出这 10 个随机数
- random.seed()是产生随机数种子的函数,random.randint()函数可以在某个数字范围内产生随机数,end 参数可以在每个输出结果后面进行逗号分隔。
第三方库
从 Python 实用性角度来讲,随着我们对 Python 的理解更深、应用更广,肯定会安装各种各样的第三方库,这些库都是大神免费开发并提供给我们使用的宝贵财富。比如我们在处理 Excel 表格时,会用到 openpyxl 库、xlsxwriter 库、数据处理库 numpy 和 pandas、包括画图库 matplotlib;在开发网站时,会用到 Django库;在编写爬虫时,会用到 Scrapy 库、requests 库、re 库;在科学数据处理时,会用到 scipy 库等等。
- 下载并安装(pip)
如同 Python 编程之前需要安装 Python 编译器一样,使用第三方库之前首先要进行第三方库的下载与安装。在此仅提供一种最为简便、实用、好用的方法,即 pip 安装,使用方法是使用 win+R 键或者在开始菜单右键打开运行对话框,输入 cmd,打开命令提示符,然后输入一行命令:
以安装 numpy 库为例
- 更换服务器
(1)临时性地更换服务器
这个方法操作非常简便,适用于新手和下载库较少的学习者。在原来 pip install <库名>的基础上加上这么一行:
(2)永久更换服务器
以清华大学服务器为例,介绍如何永久更换,也比较简单,是个一劳永逸的办法,也是三部曲:
(a)进入自己的系统用户名文件夹
(b)创建 pip 文件夹
(c)创建 pip.ini 文件并进行编辑如下内容:
3. jieba 库
jieba(“结巴”)库是用于中文文本处理、对文本词语分割的库。
各个领域第三方库的名称进行了解