给普通人的Python——第五章(上)
文章目录
- 5. 代码重复使用的艺术:函数
- 5.1 一个例子引入
- 5.2 定义函数
- 5.3 使用函数重构代码
- 请关注公众号:编程之路从0到1
5. 代码重复使用的艺术:函数
编程中的函数和我们数学中的函数内涵是不同的。简单说,编程中的函数,其实就是一组代码。那为什么要把这些代码放到一起呢?用任何语言来表达这个问题都会显得抽象和难以理解。我们不如直接回到没有函数的情况下去写代码,亲自体会发明函数的必要性。
5.1 一个例子引入
我们上次学习了如何使用“海龟”先生画图,那我们这次再复习一下用法
我们今天就来画下面这幅图
在画这种图之前,我们肯定先得画一个草图,计算好所有的坐标位置,我们用红色虚线表示坐标轴,两条虚线交点就是原点,如下
大家可以先自己画一画,代码如下
import turtle# 创建一个窗口对象,并赋值给变量window
window = turtle.Screen()# 创建一个海龟对象,并赋值给变量tt
tt = turtle.Turtle()# 抬起画笔
tt.penup()# 将画笔移动到坐标为(150,150)的位置
tt.goto(150, 150)# 落下画笔
tt.pendown()# 右转90度
tt.right(90)# 画外层的大长方形
tt.forward(450)
tt.right(90)
tt.forward(300)
tt.right(90)
tt.forward(450)
tt.right(90)
tt.forward(300)# 画顶部的直角三角形
tt.left(135)
tt.forward(212)
tt.left(90)
tt.forward(212)# 画中心的半圆形
tt.penup()
tt.goto(50, 0)
tt.pendown()
tt.left(225)
tt.circle(50, 180)# 画正方形窗户,需要注意,画完圆形后,画笔朝向已经向下
tt.penup()
tt.goto(50, 0)
tt.pendown()tt.forward(100)
tt.right(90)
tt.forward(100)
tt.right(90)
tt.forward(100)
tt.right(90)
tt.forward(100)# 画窗户中的十字
tt.penup()
tt.home()
tt.pendown()
tt.right(90)
tt.forward(100)tt.penup()
tt.goto(50, -50)
tt.pendown()
tt.right(90)
tt.forward(100)# 隐藏画笔(小三角)
tt.hideturtle()
# 不让窗口立刻退出
window.mainloop()
上面的代码密密麻麻写了60多行,我们仔细观察会发现,其中有很多是重复的代码,比如下面这一段
tt.right(90)
tt.forward(100)
tt.right(90)
tt.forward(100)
tt.right(90)
tt.forward(100)
我们人类的进步是建立在偷懒的基础上的,那就会有人想了,既然是重复的代码,那我们程序员能不能偷一下懒,少写一点呢?这里的例子只有几行重复代码,那如果是一个复杂的程序,有几百行重复的代码呢?这偷懒可不是省下一点点工作量,那是节省了大量的工作量。
这个时候就可以用上我们开头说的函数了,将相关代码放到一起,形成一组代码。修改代码如下
import turtle# 创建一个窗口对象,并赋值给变量window
window = turtle.Screen()# 创建一个海龟对象,并赋值给变量tt
tt = turtle.Turtle()# 抬起画笔
tt.penup()# 将画笔移动到坐标为(150,150)的位置
tt.goto(150, 150)
# 落下画笔
tt.pendown()
# 右转90度
tt.right(90)# 画外层的大长方形
tt.forward(450)
tt.right(90)
tt.forward(300)
tt.right(90)
tt.forward(450)
tt.right(90)
tt.forward(300)# 画顶部的直角三角形
tt.left(135)
tt.forward(212)
tt.left(90)
tt.forward(212)# 画中心的半圆形
tt.penup()
tt.goto(50, 0)
tt.pendown()
tt.left(225)
tt.circle(50, 180)# 画正方形窗户,需要注意,画完圆形后,画笔朝向已经向下
tt.penup()
tt.goto(50, 0)
tt.pendown()tt.forward(100)# tt.right(90)
# tt.forward(100)
# tt.right(90)
# tt.forward(100)
# tt.right(90)
# tt.forward(100)def repeat():tt.right(90)tt.forward(100)# 调用repeat函数
repeat()
repeat()
repeat()# 画窗户中的十字
tt.penup()
tt.home()
tt.pendown()
tt.right(90)
tt.forward(100)tt.penup()
tt.goto(50, -50)
tt.pendown()
tt.right(90)
tt.forward(100)# 隐藏画笔(小三角)
tt.hideturtle()
# 不让窗口立刻退出
window.mainloop()
如上,我们将重复的代码注释掉了(即不再生效),然后定义了一个函数叫repeat
,这个函数块里面包含两句代码,这个函数就相当于是一个组,然后调用三次这个函数,就替代了之前被注释的那段代码。我们重新运行程序,功能和之前一模一样。
使用函数封装了一组代码,今后只需要调用这个函数就可以了,这里代码量少,看不出有什么优势,我们后面会接着封装。
5.2 定义函数
我们先学习一下函数的定义方式
def
是单词define
的缩写,定义的意思。要记住,Python中的所有缩进都是4个空格。这里我们没有定义参数,所以参数列表是空的。要注意,定了一个函数,这个函数里面的代码并不会执行,只有当调用函数时,函数里面的代码才会执行!调用函数就很简单了,我们已经调用过很多次函数了,只需要在函数名后面加一对因为括号就可以。如果这个函数有参数,那么需要在括号中传入参数。
先看一个简单示例
def add(x,y):print(x + y)add(19,1)
输出结果:
20
我们定义了一个加法函数,在参数列表处定义了两个参数x
和y
,这说明调用这个函数时,必须传入两个参数,否则会报错。定义完成后,我们去调用这个函数,并传入两个参数。参数列表中的参数,其实就是一个变量,变量名可以自己取。
在定义一个函数时,应该将逻辑上的某一种功能封装成一个函数,而我们之前定义repeat
函数时,只是简单的将重复代码放到一个函数而已,在逻辑上没有什么意义。但是后面定义的add
函数就是有意义的,它对应的功能是将传入的参数相加,它是一个加法函数。
这一次我们就再深入一层,定义函数时,从功能角度去封装。首先观察我们一开始画的那幅图,我们发现它有一处重复的地方,它的最外层是一个三角形加长方形,内部呢,又有一个正方形的窗户。我们知道,长方形和正方形统称为矩形,这样我们就可以定义一个画矩形的函数,然后调用两次这个函数画两个矩形,不就完美了吗?
import turtle# 定义一个函数,画正方形。它有两个参数,第一个是画笔,第二个是边长
def draw_square(pen, length):pen.right(90)pen.forward(length)pen.right(90)pen.forward(length)pen.right(90)pen.forward(length)pen.right(90)pen.forward(length)# 创建一个窗口对象,并赋值给变量window
window = turtle.Screen()# 创建一个海龟对象,并赋值给变量tt
tt = turtle.Turtle()# 调用我们的draw_square函数,将画笔、正方形边长传进函数中
draw_square(tt, 100)tt.hideturtle()
# 不让窗口立刻退出
window.mainloop()
执行这段代码后成功的画了一个正方形,但是我们这个函数一点也不灵活,我们第二次调用的时候,它仍然在原地画了一个正方形,我们希望能传一个坐标,以这个坐标点为右上角,在指定的位置画正方形,另一个问题则是这个函数中仍然有重复的代码,我们再很早之前就讲过,重复的艺术——循环,要画四条边,那我们循环执行四次就可以了,再次改进代码
import turtle# 定义一个函数,画正方形。它有4个参数,第一个是画笔,第二、三是坐标,最后一个是边长
def draw_square(pen, x, y, length):# 抬起画笔pen.penup()# 复位画笔,主要是为了让画笔方向朝向右侧pen.home()# 将画笔移动到指定的点pen.goto(x, y)# 放下画笔pen.pendown()# 通过for循环让块中的代码循环运行四次for i in range(4):pen.right(90)pen.forward(length)# 创建一个窗口对象,并赋值给变量window
window = turtle.Screen()# 创建一个海龟对象,并赋值给变量tt
tt = turtle.Turtle()# 调用draw_square函数,将画笔、右上角x、y坐标,边长传入
draw_square(tt, 30, -100, 50)
draw_square(tt, 30, 100, 50)tt.hideturtle()
# 不让窗口立刻退出
window.mainloop()
运行上面的代码,我们成功的分别以(30, -100)、(30, 100)两个点为右上角画了两个边长为50的正方形。有了我们的draw_square
函数,我们再也不需要去写那么多代码画正方形了,每次调用这个函数就可以了,这真是写一个函数,永远受益啊,大家完成这个函数,是不是特别有成就感呢!这里一定要好好体会一下,函数的妙用,以及对代码的封装。
这段代码只有一个地方需要简单说明一下,我们在函数中调用了pen.home()
,这是因为每次调用draw_square
函数时,我们无法确定画笔在此时的朝向,如果无法确定朝向,我们也根本没办法画正方形,因为我们的画法是默认画笔朝向右侧的,然后我们调用pen.right(90)
将画笔转向朝下,然后从右上角开始朝下方画。pen.home()
函数就是将画笔复位的意思,调用之后,不管画笔曾经是什么状态,此刻它都已经复位,处于原点位置,且朝向右侧。
到这里,离我们今天的目标已经很近了,我们前面订的目标是写一个画矩形的函数,现在只是完成了画正方形,那该如何改造,让这个函数也能画矩形呢?
import turtle# 定义一个函数,画矩形。它有5个参数,与之前不同的是,我们将边长拆成两个参数,表示宽(width)和高(height)
def draw_rectangle(pen, x, y, width, height):# 抬起画笔pen.penup()# 复位画笔,主要是为了让画笔方向朝向右侧pen.home()# 将画笔移动到指定的点pen.goto(x, y)# 放下画笔pen.pendown()if width == height:for i in range(4):pen.right(90)pen.forward(width)else:for i in range(2):pen.right(90)pen.forward(height)pen.right(90)pen.forward(width)# 创建一个窗口对象,并赋值给变量window
window = turtle.Screen()# 创建一个海龟对象,并赋值给变量tt
tt = turtle.Turtle()# 调用我们的draw_square函数,将画笔、正方形边长传进函数中
draw_rectangle(tt, 30, -100, 50, 50)
draw_rectangle(tt, 30, 100, 50, 90)tt.hideturtle()
# 不让窗口立刻退出
window.mainloop()
我们首先将函数名改为draw_rectangle
,意思是画矩形。我们知道,正方形其实就是特殊的矩形,也就是边长相等的矩形。因此我们之前的draw_square
函数其实改动不大,我们只是加了一个if-else
判断,当宽和高相等时,说明是正方形,那就仍然走以前的代码,如果宽高不相等,那显然是长方形,由于长方形的特殊性,我们的代码只能循环两次,这一点结合上面的画法图很容易理解。最后我们调用draw_rectangle
在指定坐标处各画了一个正方形和长方形
到这里我们彻底实现了定义一个函数画矩形的目标,大家一定要好好体会体会这里的妙用。
5.3 使用函数重构代码
最后,使用我们编写的函数,改造最开始我们画房子的代码
import turtle# 定义一个画矩形的函数
def draw_rectangle(pen, x, y, width, height):# 抬起画笔pen.penup()# 复位画笔,主要是为了让画笔方向朝向右侧pen.home()# 将画笔移动到指定的点pen.goto(x, y)# 放下画笔pen.pendown()if width == height:for i in range(4):pen.right(90)pen.forward(width)else:for i in range(2):pen.right(90)pen.forward(height)pen.right(90)pen.forward(width)# 创建一个窗口对象,并赋值给变量window
window = turtle.Screen()# 创建一个海龟对象,并赋值给变量tt
tt = turtle.Turtle()# 画一个300x450的矩形
draw_rectangle(tt, 150, 150, 300, 450)# 抬起画笔
tt.penup()
# 将画笔移动到坐标为(150,150)的位置
tt.goto(150, 150)
tt.pendown()# 画一个直角三角形
tt.left(135)
tt.forward(212)
tt.left(90)
tt.forward(212)tt.penup()
# 移动到(50,0)位置,画一个半圆
tt.goto(50, 0)
tt.pendown()
tt.left(225)
tt.circle(50, 180)# 画一个100x100的正方形
draw_rectangle(tt, 50, 0, 100, 100)# 画窗户中的十字
tt.penup()
tt.home()
tt.pendown()
tt.right(90)
tt.forward(100)tt.penup()
tt.goto(50, -50)
tt.pendown()
tt.right(90)
tt.forward(100)tt.hideturtle()
# 不让窗口立刻退出
window.mainloop()
改造后,代码从逻辑上就异常清晰了。这一章的学习中,我们要学习好函数的使用,充分体会函数的复用性,这种重复使用不仅仅是一次性的,而是今后我们再也不需要去手动的一笔一笔的画矩形了,甚至我们还能把这个函数发给别人使用。而且有了函数后,代码变得更加清晰,一个函数就对应一种功能,以后我们会不断学习函数的使用,写代码中灵活定义函数,这样我们的代码就有了结构,再也不是一锅粥的都写在一起,这就好比写文章我们要分段,绝不是一篇文章只有一段那样。
请关注公众号:编程之路从0到1
只要关注,即可获取网盘资源!
配合本教程,还有视频讲解哦,不容错过
给普通人的Python——第五章(上)相关推荐
- 【python第五章——函数】
python第五章--函数 第五章--函数 5.1函数概述 5.2 函数进阶 下面部分之后再写 5.3函数习题(一些小例子) 第五章--函数 5.1函数概述 快速入门: #定义函数 def func( ...
- python 第五章 字典
python 第五章 # # !/usr/bin/python # # -*- coding: utf-8 -*- # # @File : 总结.py # # @time : 2019-07-1010 ...
- javascript高级程序设计 学习笔记 第五章 上
第五章 引用类型的值(对象)是引用类型的一个实例.在 ECMAScript 中,引用类型是一种数据结构, 用于将数据和功能组织在一起.它也常被称为类,但这种称呼并不妥当.尽管 ECMAScri ...
- python第五章课后题答案_python程序设计基础(嵩天)第五章课后习题部分答案
原博文 2019-10-13 13:50 − 第五章p1515.2:实现isodd()函数,参数为整数,如果参数为奇数,返回true,否则返回false.def isodd(s): x=eval(s) ...
- python第五章总结
第5章组合数据类型 5.1认识组合数据类型 (1)常用的序列类型有字符串.列表和元组. (2)序列支持双向索引:正向递增索引和反向递减索引正向递增索引从左向右依次递增,第一个元素的索引为0,第二个元素 ...
- Python第五章序列,集合,字典
一.切片 介绍 1.函数float函数和eval函数的区别: 2. 利用下标"[]"可以从字符串(列表,元组)中截取一个子串 二.浅拷贝和深拷贝 1.浅拷贝 2.深拷贝 3.哈希 ...
- python第五章课后编程题答案_Python核心编程-第五章课后习题
5-1 整形 讲讲 Python 普通整型和长整型的区别 答:在2.7版本基本淡化了区别.真要区分的话,普通整型是32位或者64位,而长整型只与PC内存有关,很大就是了 5-2 运算符 (a) 写一个 ...
- python第五章_Python数据分析-第5章Series(下)
2,指数加权移动平均的意义 指数加权移动均值(EWMA,Exponentially Weighted Moving Average) 的公式是:EWMA(t) = aY(t) + (1-a)EWMA( ...
- python第五章课后题答案超星_MOOC网课章节答案_Python 语言程序设计见面课测试答案...
[单选,A1型题] 能疏肝.暖肝,治肝寒气滞诸痛的是() [单选,A4型题,A3/A4型题] 男,32岁,进食后上腹饱胀不适,伴返酸.烧心.嗳气.食欲不振,临床诊断为慢性胃炎.该病治疗中不正确的是() ...
最新文章
- Cell子刊:辛秀芳组发现病原菌效应因子操纵植物ABA激素通路促进侵染的新机制...
- adc0808温度换算公式_温湿度传感器的三种模拟量换算关系
- 019_MySQL正则表达式
- Linux 查看I/O端口地址分配
- Java中利用socket实现简单的服务端与客户端的通信(基础级)
- redis-cli 命令详解
- LoadRunner 常用C语言函数使用
- 什么是SAP Spartacus schematics
- .bash_profile vs .bashrc
- 【转】20个让Web Developer开发生涯更加轻松的工具
- elementui 嵌套表单验证_elementUI 表单嵌套表格验证,日期选择器联动限制等写法
- 靠着零代码报表工具,转行报表开发后月薪超过3万
- android--04activity的布局管理器
- Linux之SELinux自主访问控制系统
- 茆诗松等《高等数理统计(第二版)》例 1.28 的错误及改正
- 四种XML解析方式详解
- Android Camera processCaptureResult 分析
- python二进制转十进制函数_python基础教程之python基础教程之python进制转换(二进制、十进制...
- 2020东三省数学建模A题
- W74 - 999、云计算工程师认证