Python少儿编程
·
20
篇内容
推荐文章
下一页

少儿Python编程_第二十讲 编程技巧

在学习编程的过程中,起初新手开发者对程序没有什么概念,先讲解习惯和注意事项,不但没什么效果,注意事项太多,反而提高了编程的难度;往往在自己遇到问题后,经过思考,印象更加深刻。之前在每一讲课后练习中,也加入了一些技巧说明,但比较分散。本讲将总结编写程序过程中遇到的各种问题和编程习惯。

20.1 编程习惯

写程序最重要的是实现功能,在实现功能的基础上,好的编程习惯,让代码更清晰,更容易理解,无论是过一段时间自己再看,还是给别人使用都能节约大量时间;同时,好的编程习惯让代码在不同运行环境和操作系统中也能稳定地运行。

20.1.1 缩进

缩进指代码与边界之间的距离,Python使用缩进组织代码块,一般用冒号和缩进区分代码之间的层次。代码块缩进常出现在:函数体、循环体、以及判断语句之后。

对Python编程来说,缩进是必不可少的;其它编程语言,也大都包括缩进,但有的不是必须缩进,比如C语言用大括号括住循环体内容,但一般程序员也会使用空格缩进,这样更容易看到代码的层次:直观地看到循环从哪里开始,到哪里结束,缩进也是一种良好的编程习惯。

1.缩进相关错误

<pre style="tab-stops:21.75pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt">

缩进的英文是Indentation,在报错信息中看到相关的单词,如“unexpected indent”,就需要注意,可能是缩进错误。

<pre style="tab-stops:21.75pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt">

有一种常见的错误是:缩进中间断开,如下例所示:

01 if x>0:
02     print("x>0")
03 print(x)
04     print("ok")

编写这段语句的本意是:需要在x大于0时打印02和04句,无论什么情况都打印第03句。但使用以上写法,第三句没有缩进,表示if条件对应的代码块在02句之后已经结束,第04句的缩进出错。

冒号表示一个新代码块的开始,行尾的冒号和新增的缩进一一对应,只有冒号没有新的缩进,或者没有冒号但有新的缩进都是错误的,代码块中间不能断开。

正确的方法是调换第03句和04句的位置。

2.缩进的空格数

缩进使用的空格数是可变的,一般情况下,使用四格缩进,但也有人习惯两空格缩进或八空格缩进。在同一程序中必须使用一致的缩进规则,建议使用默认的四格缩进。

3.Tab键生成缩进和空格生成缩进

Tab键输入制表符,用于文本对齐,制表符在不同软件中被显示成四个或者八个空格。在Jupyter Notebook或者Spyder等编程工具中,使用Tab键生成的制表符都被转换成了对应的空格,因此可以使用Tab键生成缩进。但使用Windows记事本这类纯文本编辑器时,不自动转换成空格,如果混用Tab键输入的制表符和空格,程序运行时就会报错,由于制表符和空格看起来差不多,这种错误很难通过观察发现。

20.1.2 命名

无论是编写程序还是使用文件都会遇到命名问题,比如函数名、类名、变量名、文件名、路径名、网址、数据库的字段名等等。计算机上的命名规则也大同小异。一般都支持英文字母、数字、下划线,有的命名也支持中文、特殊符号、空格等等,虽然有些命名规则支持上百个字符的命名长度,但习惯上一般都在20字符以内,不应太长。

1.有意义的命名

命名最重要的是有意义,让自己和他人通过名字可以了解变量或者文件的作用。尽量不要使用a、b这样的命名,很难查找,时间长了自己也会忘记用途。

2.中文和特殊符号

Python 3之后的版本,支持用中文命名变量,Windows也支持用中文命名文件和目录。由于在计算机中支持多种中文编码,使用不同软件或者系统打开文件时,默认的编码方式如果不同,则可能出现乱码;另外,有些系统区分大小写字母,有的则视大小写为同一字母。

在编写程序时,尽量使用小写英文字母数字和下划线命名,最好使用有意义的英文单词,其次是使用拼音,尽量少使用中文命名变量、函数和类,除了下划线“_”,命名时也尽量少使用其它的特殊符号和空格,如果想用一个以上的词命名变量,建议使用下划线分隔词,例如“get_width”相比“getwidth”更加直观。

另外,还需要注意区分下划线“_”和减号“-”;中英文标点符号不同;一些字符看起来比较像,比如大写的i(I)和小写的L(l),英文字母O和数字0比较容易混淆等等。

3.命名习惯

注意根据用途命名,例如:主要给老师、同学、家长(中国人)看的文件名、目录名可以用中文命名;给程序员看的代码文件名、代码中的内容、数据库字段使用英文字母命名;提供给别人调用的文件或者函数命名要有意义,只供自己使用的内部变量可相对随意一些。

另外,还有一些约定俗成的用法,比如:一般使用字母i,j表示循环中的记数变量。对于一些不变的值,通常使用大写字母命名,比如窗口的长宽常使用WIDTH和HEIGHT命名。

20.1.3 注释

1.用途

注释是对代码的解释和说明,它的目的是让人能够更加轻松地理解代码。虽然使用有意义的命名可以描述程序文件、函数、变量的功能,但命名不能太长,一般通过注释进行更加详细的说明。注释有以下几种使用场景:

  • 在程序文件的开头介绍该程序的功能和用法。
  • 在函数之前介绍函数的功能和用法。
  • 在难以理解的语句前后,说明语句的功能。
  • 将暂时不用的代码注释掉。

注释要尽量写得简洁而清楚,如果不熟悉英文,就用中文写,内容比形式更重要。不光自己看得懂,也要让别人能看懂。

2.用法

Python使用井号“#”实现单行注释,当前行中井号之后的内容都视为注释。使用三引号实现多行注释,形如:

01 print('aaa') # 打印信息
02 """
03 注释第一行
04 注释第二行
05 """

三引号用于定义包含回车换行的字符串,可以是三个单引号,也可以是三个双引号。在程序中的字符串,不操作、不赋值,也不影响程序的运行,因此,常作为包含多行的注释使用。

20.2 调试程序

学习自然语言时,除了记住词义以外,还要能组合成句子文章,才能正常使用。编程语言也是一种语言,学习时不仅要记住所学知识点,还要学习程序整体的构造和调试。在每一讲后面的习题可供读者练习编写各种程序。尤其是从第十五章之后,不再对课程中实例的简单修改,而是用完全不同的代码构造新的功能。

如果读者按要求完成了练习,在练习过程中一定遇到了很多的程序错误,也从中学习了解决问题的方法。

本小节将总结常见的问题和解法,并介绍简单有效的程序调试方法。

20.2.1 常见问题

无论是使用命令行还是Python集成开发环境,程序运行出错时都会显示错误提示。提示信息中最重要的是行号信息,开发者通过行号可以确定错误的大概位置。

1.语法错误

图20.1 语法错误示例

图20.1是一种常见的错误,“invalid syntax”意思是语法错误,提示错误出现在第二行(line 2),实际上,错误的原因是第一行少了右括号,程序一直在等待右括号,而在第02行却出现了print语句,所以提示为第02行错误。由此可见,也有少量错误行提示,可能是由之前行的错误引起的。但至少可以通过行号确认大概位置。

2.缩进错误

图20.2是缩进错误,“unexpected indent”意思是意外的缩进,它由第2行多了一个空格引起,也是常见的输入引起的错误。

图20.2 缩进错误

3.名字未定义错误

图20.3示例了未定义错误,程序在使用y之前,没有定义y,因此提示“name ‘y’ is not defined”(名字’y’没有被定义)。有时候,并不是使用变量或者函数前没有定义,也可能是没有引入函数所在的三方库、或者是输入时拼写错误引起的,比如:混淆字母O和数字0,逗号看成句号,冒号和分号写错等等。像大写I(i)和小写l(L)混淆的错误很难被观察到,这时,可以使用查找功能,比如在Jupyter Notebook中用Ctrl+f查找报错中提示的名字。

图20.3未定义错误

4.下标越界错误

图20.4示例了下标越界错误,报错为“list index out of range”(列表索引号超出范围),程序在第1行定义了含有三个元素的列表arr,在第2行试图访问数组的第4个元素(索引号为3),数组元素索引号从0开始,范围是0,1,2,本例中访问的索引号超过了列表的最大索引号。

图20.4 下标越界错误

5.其它问题

程序可能出现的错误非常多,无法一一列举,而报错信息一般都是英文的,建议使用以下步骤查找错误原因:

首先,查看错误提示中的行号,以及行号之前的程序,看是否能发现代码错误。

如果未找到原因,查看是否为以上几种错误类型。

如果不是以上问题,用翻译工具翻译错误提示,以定位问题。

如果仍不能找到问题,在搜索引擎(如百度)中搜索错误提示,查看他人解决此类问题的方法。

20.2.2 调试方法

在程序中间加入断点和打印信息都是标准的程序调试方法,特别是在运行他人编写的代码时,用这种方法可以了解每个阶段做了什么。

我们写的程序都相对简单,类和函数并不多,当运行别人代码时,梳理互相调用关系很重要,最好能画出简单的调用关系图。

1.print 函数

Python中的print函数用于打印输出,它虽然不是专用的程序调试工具,但是如果养成使用print跟踪程序运行的习惯,至少一半的问题都可以解决。

学习使用print调试程序不是学习函数的使用方法,而是在编写程序的过程中,要理解程序每一行做了什么工作,每一行程序执行之后当前环境中各个变量的状态是什么,尤其是在循环这样较为复杂的结构中,需要了解每一次循环中数据的变化。而使用print语句则是在开发者不太清楚当前状态的情况下,用程序输出所关注的变量或者数据。

比如加载数据表文件之后,可以用print语句显示加载后的内容以及数据格式,又如跟踪循环中数据的变化情况。如下例所示。

01 s = 0
02 for i in [1,2,3]:
03     s = s + i * 7
04     print(s, i)

其中第四行用于显示每一次循环中的s值和i值。当程序并未报错,但输出结果与想象中不同时,可以使用print方法跟踪程序中数据的变化,以定位出错的位置。

还有一种常用的调试方法是注释掉可能错误的程序段,然后运行程序,如果运行仍不正常,说明不是被注释掉语句的问题,继续注释更多的语句;如果注释后运行正常,则说明是该段问题,然后尝试注释掉较少的语句,直到定位到具体出错的行。

2. 调试工具pdb

pdb是Python的调试工具,由于pdb使用方法比较复杂,此处讲解pdb只作为知识扩展,不要求读者掌握。

在Jupyter中加入魔法命令%pdb,即可在程序出错时调用pdb,以便调试出错时的具体代码。例如,运行以下程序:

01 %pdb
02 arr = ['a','b','c']
03 print(arr[3])

程序运行到第三行时,会报错,但并未退出,界面上将出现可交互的输入框,开发者可以在输入框中输入程序如:print(arr),来进一步运行程序。请注意:调试完成之后需要在输入框中输入exit退出调试模式。

使用pdb的另一种方法是在程序中加入断点,当程序运行到该行,会跳出可交互的输入框,开发者可以通过pdb命令查看当前状态,或者逐步执行断点之后的程序。

设置断点的方法是,在程序中加入pdb.set_trace(),如以下程序所示:

01 import pdb
02 arr = ['a','b','c']
03 pdb.set_trace()
04 print(arr[3])

pdb常用的调式命令如下:

  • 单步调试(进入函数):s(tep)。
  • 单步调试(不进入函数):n(ext)。
  • 继续往后执行,直到下个断点:c(ont(inue))。
  • 运行到函数结束:r(eturn)。
  • 运行到当前循环结束:unt(il)。
  • 设置断点:b(reak) 文件名:行号(或行号,或函数名)。
  • 显示当前调用关系:w(here)。
  • 显示当前代码段:l(ist)。
  • 显示变量:p(rint) 变量名。
  • 显示当前函数的参数:a(rgs)。
  • 显示帮助信息:h(elp)。
  • 退出:q(uit)。

20.2.3 错误处理

程序有时可能出现一些难以预料的错误,比如写客户端程序与服务器端交互,就可能遇到很多问题,如网络未连接,对三方库调用方法不对,与服务器数据交互格式不对,或者以前能正常运行,后来服务端修改了端口,找不到对应功能等等。

这种情况下,程序员,尤其是写程序供他人调用的程序员,需要识别出程序中可能出现的错误,进行错误处理后,保证程序正常运行,而不会意外退出。

当程序运行出错时会抛出异常,如果不做处理,则程序会异常退出,Python用try/except方式捕获异常,其语法规则如下:

01 try:
02     程序代码
03 except <异常类> as <变量>:
04 异常处理代码
05 else:
06     异常以外其它情况处理
07 finally:
08     无论是否异常,最终都要执行的代码

简单实例如下:以读方式打开文件test.txt,该文件不存在时将抛出异常,例程中捕获异常,并显示出具体的异常信息。

01 try:
02     f = open('test.txt', 'r')
03 except Exception as e:
04     print('error', e)
05 print('aaaa')
06 # 返回结果:
07 # error [Errno 2] No such file or directory: 'test.txt'
08 # aaaa

从返回结果可以看到,捕捉到异常信息后,程序正常执行了之后的打印信息操作,而并未因为异常而崩溃。

课后练习:(练习答案见本讲最后的小结部分)

练习一:尝试捕获越界的错误。

20.3 思维训练

20.3.1 学习编程的好处

如果读者从头到尾学习了所有例程,并做完了所有习题,可能发现以下变化:

  • 熟悉了程序、界面、网络、数据库、数据分析等概念。
  • 熟练使用Python编程环境。
  • 对大多数问题都能定位到关键点。
  • 写程序从修改变成了构建。
  • 不再抵触较长的程序段。
  • 变量命名更有章法。
  • 更喜欢使用工具和快捷键。
  • 能解决大多数语法方面的问题,至少有了解决思路。
    ……

12岁以下的学生,对于文中绝大多数的概念都是第一次接触,即使当时学会了,过一段时间也会淡忘,因此推荐整体看三遍以上,最终目标是能自如地编写练习中的每一个程序,并且能够将程序用于日常的数据处理。

20.3.2 防患于未然

之前提到学习常常分为两部分:一部分从经验中学习,即构建框架;另一部分从教训中学习。经验可以通过实践或者学习规则构造,而教训更多往往是自己犯了错误印象才深。

教训又可再细分成两种情况:改正错误和防患于未然。发现问题及时改正可能导致处理过程的暂停和回退;而防患于未然则更多地源于之前的积累,它们在错误的行为之前就进行了阻止,而从表面看来,似乎非常平稳,未经波折。实际上是经验在毫无意识的情况下就发生了作用。比如我们不会在公共场景提到禁忌话题。

因此,很多时候看起来运气比较好或者天生的灵感,实际上下意识的行为是源于之前的积累。对于一个严谨的人,很多思路在没有外显时可能就已经被过滤掉了,往往也显得没有幽默感,缺少想象力。严谨或者随意可能取决于个人经历和环境,也可能是遗传或者性格所致。

人们不能要求小孩子对陌生人又友好,又有戒心,但是有些成年人却可以做到。我们在成长过程中不断打磨,逐渐学会了在两极之间取折中的方案,在不同的情况下使用不同的框架。

20.3.3 注意事项

最后,整理了一些学习编程中的注意事项,与大家共同学习:

  • 任何老师都不可能列出所有可能出现的问题,要学会在试错中进步。
  • 基础知识非常重要,无论文科理科记和背都是必须的,对常用知识构建条件反射,才能有更多的脑力用于后续的学习和思考。
  • 完成功能后整理代码:从变量命名到代码顺序,都请严格要求自己。
  • 量的问题积累太多,就变成了质的问题:一个小问题,努力一下也许能解决,但是十个小问题堆叠起来,脑子就直接转不动了。
  • 代码重构比代码填空难度大得多,尽量多练习构建整体代码逻辑。
  • 分类和对比非常重要,如果不能直接找到答案,可以寻找类似的情况及处理方法。
  • 代码需要逐行读懂,长代码,很可能读到后面忘了前面,建议边读边记,最好能绘制流程图,有时候也需要反复阅读。
  • 初学者对例程往往知其然,不知其所以然,在看他人代码时尽量动手跟踪调试程序。
  • 写程序像弹琴一样需要不断练习,即使学一遍就会,后边不用也会很快忘记。

20.4 小结

20.4.1 单词

本讲需要掌握的英文单词如表20.1所示。

表20.1本讲需要掌握的英文单词

20.4.2 习题答案

  1. 练习一:尝试捕获越界的错误。
01 try:
02     arr=['a','b','c']
03     print(arr[3])
04 except Exception as e:
05     print('error',e)
06 print('aaaa')

少儿Python编程_第十九讲 数据分析网站

本讲是一个综合实例,结合了数据分析和构建网站技术,提供用户通过浏览器上传文件,在服务端实现分析上传的数据,并生成动态统计表格,回传给用户端。其中用到表单上传文件、读取Excel数据表文件、统计图表、生成动态网页等技术。

19.1 上传文件

让用户上传文件,处理后再把结果返回给用户,是一个很常用的操作,比如用户上传一张相片,服务器端经过美颜或者换背景处理后显示在网页上;又如用户上传一个Excel数据表文件,数据统计分析后把统计结果显示给用户。开发者提供前端和后端服务。用户使用网络中任意一台计算机或者手机,只需要用浏览器即可实现需要的功能,无需安装任何软件。

上传文件功能也可通过表单实现。本例展示了上传文件的方法。为简化代码逻辑,将HTML模板也写入了Python代码。

01 from flask import Flask,request,redirect,url_for
02 import os
03  
04 UPLOAD_DIR = "files"
05  
06 app=Flask(__name__)
07  
08 @app.route("/upload.html")
09 def page1():
10     return """
11 <html>
12     <h1>请上传文件</h1>
13     <form action="show.html" method=post enctype=multipart/form-data>
14         <input type=file name=upload_file>
15         <input type=submit value='上传'>
16     </form>
17 <html>
18     """
19  
20 @app.route("/show.html", methods=["POST","GET"])
21 def page2():
22     if request.method=="POST":
23         file = request.files['upload_file']
24         if file:
25             if not os.path.exists(UPLOAD_DIR):
26                 os.mkdir(UPLOAD_DIR)
27             file.save(os.path.join(UPLOAD_DIR, file.filename))
28             return "上传成功"
29     return redirect(url_for('page1'))
30  
31 app.run(host="0.0.0.0", port="8088")

第01行引入flask模块中的几种方法:Flask用于建立服务,request用于接收用户传来的数据,redirect用于网页跳转,url_for用于查找函数名对应的路径。
第04行定义了存储上传文件的目录。
第08-18行定义了函数用于提供用户选择文件和上传文件的界面。
第08-09行关联了网址中的路径与函数,当用户在浏览器中打开“/upload.html”时调用函数page1。
第10-18行描述了返回的HTML文件,使用三个双引号可定义带有回车的字符串。读者也可以将这段代码写成文件,放在templates目录下,在程序中用render_template函数加载。
第13-15行定义了表单,表单提交时以POST方式访问路径“show.html”。
第14行添加了选择上传文件的控件,并将该控件命名为upload_file,以便程序读取。
第20-29行定义了用户上传文件后的响应界面。
第22行判断是否为“POST”请求。
第23行获取上传的文件,赋值给变量file。
第24行判断file变量是否正常。
第25-26行判断保存文件的目录是否存在,如果不存在,则创建该目录。
第27行使用文件保存路径加文件名,构造文件在服务端的存储路径。
第28行向客户端返回“上传成功”字符串。
第29行用于处理在非“POST”请求的情况下,跳转到page1对应的地址upload.html继续显示上传文件界面。

程序运行结果如图19.1所示:

图19.1文件上传界面

19.2 PyEcharts

探索性数据分析简称EDA,它是通过图表方式探索数据的结构和规律的一种数据分析方法。常用的方法有直方图、箱线图、变量分析等等。

Echarts是一个用Javascript实现的商业级数据图表工具,它可以流畅的运行在计算机和手机设备上,兼容当前绝大部分浏览器。Pyecharts是Python版本的Echarts,它的使用方法类似前面讲过的matplotlib,虽然它主要用于网页显示,但可以在Jupyter Notebook中调试,并且生成HTML文件。调试的显示效果和HTML页面效果完全一样。与其它EDA工具相比,它使用更方便,配色方案也更加考究。

之前学习了使用Matplotlib绘制图表,Matplotlib虽然能实现绝大多数的图表绘制,但默认字体和配色效果都不太美观,如果想做出高级的图表,需要设置大量的参数,虽然它也能将图表保存成图片,但只支持静态图片,且嵌入网页操作比较复杂。

PyEcharts解决了以上问题,它可以生成与用户交互的动态网页,有完美的字体和配色方案,用简单方法绘制复杂图片,并且可以方便地与Flask框架配合使用。

本节将介绍PyEcharts的使用方法。

19.2.1 准备环境

1.安装软件

在使用PyEcharts之前需要用以下命令安装模块,PyEcharts不同版本使用方法不同,本例中使用了当前的默认版本1.4.0。在Windows中打开:开始->所有程序->Anaconda 3->Anaconda Prompt,在终端输入:

01 $ pip install pyecharts

2.数据准备

将表19.1中的数据存入Excel数据表test.xlsx,作为数据分析的素材。表中共有9条记录,8个字段,包括字符型(姓名)、类别型(性别、类型、年龄、出场频率),数值型(智力、体力、颜值)。

表19.1 待分析的数据表

19.2.2 绘制柱状图

柱状图非常实用,本例展示了在同一张图中显示多柱对比效果的方法,对比了智力和体力两个特征,将每个人的智力和体力用不同颜色的柱表示:

01 import pandas as pd
02 from pyecharts import charts
03 from pyecharts import options as opts
04  
05 df = pd.read_excel('test.xlsx')
06  
07 bar = charts.Bar()
08 bar.add_xaxis(df['姓名'].tolist())
09 bar.add_yaxis("智力", df['智力'].tolist())
10 bar.add_yaxis("体力", df['体力'].tolist())
11 bar.set_global_opts(title_opts=opts.TitleOpts(title="喜羊羊与灰太狼"))
12 bar.render('test.html')
13 bar.render_notebook()

第01行引入了数据表支持模块Pandas,并将其重命名为pd。
第02行引入了绘图模块PyEcharts的子模块charts用于绘制图表。
第03行引入了绘图模块PyEcharts的子模块options并重命名为opts用于设置参数。
第05行读入数据表文件test.xlsx,并将其内容赋值给变量df,注意将数据文件放在与程序相同的目录中。
第07行创建了Bar对象用于绘制柱图。
第08行设置了柱图的横坐标数据为姓名字段的内容,设置前将数据格式转换为列表。
第09行设置了柱图的纵坐标数据,第一个参数为显示的文字,第二个参数为柱的高度,本行设置了智力字段的内容。
第10行设置了柱图的纵坐标数据为体力字段的内容,工具用不同颜色区分不同的数据。
第11行将标题设置为“喜羊羊与灰太狼”,其中用到了opt模块的标题参数工具TitleOpts。
第12行将图表数据渲染后保存到test.html文件中,此时当前目录下产生了新文件 test.html,如果test.html已经存在,程序将替换文件内容。
第13行将图表内容显示在Jupyter Notebook窗口之中。

程序运行结果如图19.2所示:

图19.2 柱图效果

在Jupyter Notebook中,可以显示图表的动态效果:将鼠标放在柱上,可以反馈当前柱对应的数据。

19.2.3 绘制饼图

饼图使用的数据和其它图表不同,需要指定每个区域显示的文字以及对应的数量。

01 pie = charts.Pie()
02 m = len(df[df['性别']=='男'])
03 f = len(df[df['性别']=='女'])
04 data = [['男',m],['女',f]]
05 pie.add("", data, radius=[60, 150],)
06 pie.render('test.html')
07 pie.render_notebook()

第01行创建了Pie对象用于绘制柱图。
第02行统计了性别为男的实例数量,本例中为6个。
第03行统计了性别为女的实例数量,本例中为3个。
第04行构建了两层列表,外层对应饼图中划分的不同区域,内层的两个值分别是:显示的文字及对应的大小。
第05行将数据加入饼图,其中radius参数指定了饼图内圈和外圈半径。

程序运行结果如图19.3所示:

图19.3 饼图效果

19.2.4 绘制折线图

折线图的绘制方法类似柱图,本例中除了绘制基本的折线图,还加入了图中最大值、最小值、以及平均值虚线的显示。

01 bar = charts.Line()
02 bar.add_xaxis(df['姓名'].tolist())
03 bar.add_yaxis("智力", df['智力'].tolist(),
04          markline_opts=opts.MarkLineOpts(data=[opts.MarkLineItem(type_="average")]),
05          markpoint_opts=opts.MarkPointOpts(data=[opts.MarkPointItem(type_="max")]))
06 bar.add_yaxis("体力", df['体力'].tolist(),
07          markline_opts=opts.MarkLineOpts(data=[opts.MarkLineItem(type_="average")]),
08          markpoint_opts=opts.MarkPointOpts(data=[opts.MarkPointItem(type_="min")]))
09 bar.set_global_opts(title_opts=opts.TitleOpts(title="喜羊羊与灰太狼"))
10 bar.render('test.html')
11 bar.render_notebook()

第01行创建了Pie对象用于绘制柱图。
第03-05行设置了柱图的纵坐标数据智力,第一个参数为显示的文字,第二个参数为柱的高度,参数markline_opts用于设置标志线,这里用标志线显示了均值average,参数markline_opts用于设置标志点,此处将显示最大值max点为标志点。
第06-08行设置了柱图的纵坐标数据体力,标签线设置为均值average,标志点设置为最小值点。

程序运行结果如图19.4所示:

图19.4折线图效果

本节介绍了三种常用图表,Pyecharts还支持更多的图表,不同版本的Pyecharts的函数调用方法也有差异,因此想自如地使用该模块,需要学会从三方模块自带的例程中学习使用方法,更多实例请参考:https://github.com/pyecharts/pyecharts的example目录下的例程。

课后练习:(练习答案见本讲最后的小结部分)

练习一:从git的pyecharts示例代码中学习一种之前没学过的图表,在Jupyter Notebook中正常运行,并讲述每行程序的作用。

19.3 显示图表网页

以上几个实例中用render方法将动态网页保存成HTML格式的文件,只要在Flask框架中需要显示图表处返回该网页的内容就可以在客户端的浏览器中正常显示图表。

以下实例结合了本讲学习的上传文件和制作图表功能,根据用户上传的Excel文件生成图表,并将结果反馈给浏览器显示图表。

01 from flask import Flask,request,redirect,url_for,render_template
02 import os
03 import pandas as pd
04 from pyecharts import charts
05  
06 UPLOAD_DIR = "files"
07 app = Flask(__name__)
08  
09 @app.route("/upload.html")
10 def page1():
11     return """
12 <html>
13     <h1>请上传文件</h1>
14     <form action="show.html" method=post enctype=multipart/form-data>
15         <input type=file name=upload_file>
16         <input type=submit value='上传'>
17     </form>
18 <html>
19     """
20  
21 @app.route("/show.html", methods=["POST","GET"])
22 def page2():
23     if request.method=="POST":
24         file = request.files['upload_file']
25         if file:
26             if not os.path.exists(UPLOAD_DIR):
27                 os.mkdir(UPLOAD_DIR)
28             filename = os.path.join(UPLOAD_DIR, file.filename)
29             file.save(filename)
30             df = pd.read_excel(filename)
31             bar = charts.Bar()
32             bar.add_xaxis(df['姓名'].tolist())
33             bar.add_yaxis("智力", df['智力'].tolist())
34             bar.add_yaxis("体力", df['体力'].tolist())
35             bar.render('templates/test.html')
36             return render_template('test.html')           
37     return redirect(url_for('page1'))
38  
39 app.run(host="0.0.0.0", port="8088")

本例中的大部分代码来自前面例程,因此不再逐行讲解,只介绍特殊部分。
第01-20行代码引入头文件,并实现上传文件界面。
第21-37行对上传的文件数据分析做图,将其结果返回给客户端。
第29行将上传的文件存储在服务器端的文件之中。
第30行打开保存的数据表文件。
第31-35行绘制图表,并将图表存储在'templates/test.html'文件中。
第36行将test.html文件内容返回给客户端,需要注意的是第35和36行中的test.html是同一文件,由于调用方式不同,第35行用pyecharts保存时指定了全路径。而36默认从模板目录读取文件,因此不加入模板目录名。

课后练习:

练习二:用Excel数据表创建一个小学生从一年级到六年级12个学期语文、数学、英语各科成绩的数据表,使用浏览器上传到服务器,服务器用折线图绘制其各科成绩的曲线,并在图中标出语文的平均分、最高分、最低分。做饼图分析英语成绩为“优秀”的比例(大于等于90分认为优秀)。

19.4 思维训练

19.4.1学方法和学知识

有一次,我让某位小朋友查一查“红果酱”怎么做,于是她去百度搜索到一个“一斤红果加一斤糖”的做法,我隐约觉得糖是不是放太多了?于是我也用类似方法搜索,找到三种排名靠前的三种不同做法,最终将红果和糖的比例确定为5:3,并按照多数帖子中描述的步骤进行了操作。当面对同一个陌生的问题,不同人有不同的处理方法。

在这个过程中,成人的常识起到了一定作用,成人能估计出一斤糖的甜度。而对比多种教程则是一种通过“数据”训练“模型”的方法,把脆弱的单一方法,扩展成实现目标的多条路径,以便处理更多的突发状况。另外,还有一些小技巧,比如查看美食攻略的排名、点赞数等等。可以说,这不仅是儿童和成人的区别,而是学习方法的区别。

在这个信息爆炸的时代,学习一门技能不再需要报班、买书,网络上有大量唾手可得的教程、视频,水平也良莠不齐(培训班也存在同样问题)。学习对大多数人来说,学习已经不仅是努力、认真、听老师的话;更高阶的技能是辨别学习资料的品质、合理安排时间和强度,寻找最优的途径,以及能客观地认识自己和评价外界的信息。

时代不同了,我们拥有了更多选择,判断力也比以往更加重要。如何培养判断力?判断一个教程和买一件衣服的规则不同,而货比三家、以及强大的常识系统是所有判断的基础。常识系统来自于行千里路读万卷书,尝试更多新鲜事物,而学习和思维的方法则源于通过有目标的训练培养出的良好习惯。

来看看机器人是如何学习的。Toyota正在开发一款厨房机器人,首先,让机器人拥有了视觉、触觉、运动,以及与人交流的基本能力,然后训练做具体工作的能力:比如通过多次训练机器人从架子上拿东西,以适应于不同环境,不同的架子,不同的光线,处理意外情况……同样也是先构建基本技能和学习方法,然后学习各种具体的技能。这种模仿式的学习,不再需要海量的数据训练,使机器人可以通过少量学习即可掌握各种家务技能,相比另一个只具有精准抓取技能的机器人,虽然没那么准确,但适用于更多场合。

人也是一样,把一项技能训练得再精准,也没有机器精准。从工厂的蓝领,到实验室的白领,谁又能保证你的技能有一天不会被机器人取代。学霸学方法,学渣学知识。而拥有学习的技能,长远看,可以用短时间培养出新技能,永不过时;近期看,也省了不少报补习班的费用。

19.4.2 规则与练习

除了数学或者神学这些人造领域,现实中基本没有用之四海皆准的方法,拥有的方法越多能力越强。最重要的两种学习方法是:在练习中领悟和直接学习规则,它们各有利弊。如果需要快速提高,学习规则肯定是捷径,使用同样的时间和精力,的确能让人暂时领先;从素质教育的角度看,如果有足够时间,建议多做练习,毕竟练习具体技术的过程也是对比、总结、提炼,泛化,建立内部框架的过程。

在反复练习一项技能,尤其在寻找一个问题多个解法的过程中,一些子模块会反复出现,并且可以重用。比如练字过程中,虽然常用字有几千个,但是基本笔划只有几种,每种笔划写法也有限,随着练习越来越多,即使没人告诉你“捺”的几种写法,也能训练成一种习惯。与此相对的是学习一些前人总结好的规则,比如永字八法,代入已有的规则,也能让人在短时间内快速提高水平。

规则往往是使用语言描述的链式结构,而通过练习得到的是交叉连结的网状结构。使用语言表达时,由于只能提取主干,看起来没什么区别。但是链式结构非常脆弱,只要其中一个环节断开,整个链条就会完全失效,而网状结构中通向终点的路径不只一条,具有足够的健壮性。

19.4.3 复习和复用

学习也没有捷径,再好的方法离不开反复训练。复习可以加强记忆,大多数情况下,只有被反复使用的技能才能记住;另外,在多次做同一件事的时候,内部便开启了“优化”过程:解决一个问题可能涉及很多因素,其中哪些重要,哪些只是偶然发生?如果只做一次,可能永远都无法了解。

另一个技巧是学习一些类似的技能,网状结构中很多区域都可以被复用。当你学习了素描、色彩、书法、漫画,共性的部分被一次次激发,相对于单一的链条,将更能找出其重点,并且融会贯通。尤其是对于无法用语言描述的技能,练习一段时间画画之后再练习书法,就感觉上手很快,练习书法的过程中,绘画水平也有所提高。

学习每一种技能都需要花很多的时间和精力,这并不容易,如果钢琴已经学有小成,就更愿意继续学习钢琴,而不是从头再学小提琴。然而大多数人学习钢琴的目标都不是成为音乐家,少年儿童成长阶段主要以培养能力为主,建议做更多尝试。

19.5 小结

19.5.1单词

本讲需要掌握的英文单词如表19.2所示。

表19.2本讲需要掌握的英文单词

19.5.2 习题答案

1.练习一:从git的pyecharts示例代码中学习一种之前没学过的图表,在Jupyter Notebook中正常运行,并讲述每行程序的作用。

第一步:打开网址https://github.com/pyecharts/pyecharts
第二步:在网页下方的Demo中找一个感兴趣的图表,记住名字。
第三步:打开代码的examples目录,找到名字对应的示例代码。
第四步:将示例代码复制到自己的Jupyter Notebook文件中。
第五步:把程序中的render改成render_notebook,然后运行程序。
第六步:分析程序时注意:创建需要的控件,用add函数加入待分析的数据,用opt设置需要显示的特征属性。

2. 练习二:用Excel数据表创建一个小学生从一年级到六年级12个学期语文、数学、英语各科成绩的数据表,使用浏览器上传到服务器,服务器用折线图绘制其各科成绩的曲线,并在图中标出语文的平均分、最高分、最低分。做饼图分析英语成绩为“优秀”的比例(大于等于90分认为优秀)。

设计数据如表19.3所示:

表19.3 学习成绩数据
01 from flask import Flask,request,redirect,url_for,render_template
02 import os
03 import pandas as pd
04 from pyecharts import charts
05 from pyecharts import options as opts
06  
07 UPLOAD_DIR = "files"
08    
09 app=Flask(__name__)
10    
11 @app.route("/upload.html")
12 def page1():
13     return """
14 <html>
15     <h1>请上传文件</h1>
16     <form action="show.html" method=post enctype=multipart/form-data>
17          <input type=file name=upload_file>
18          <input type=submit value='上传'>
19     </form>
20 </html>
21 """
22  
23 @app.route("/show.html", methods=["POST","GET"])
24 def page2():
25     if request.method=="POST":
26         file = request.files['upload_file']
27         if file:
28             if not os.path.exists(UPLOAD_DIR):
29                 os.mkdir(UPLOAD_DIR)
30             filename = os.path.join(UPLOAD_DIR, file.filename)
31             file.save(filename)
32             df = pd.read_excel(filename)
33             pie = charts.Pie()
34             m = len(df[df['英语']>=90])
35             f = len(df[df['英语']<=89])
36             data = [['90',m],['89',f]]
37             pie.add("", data, radius=[60, 150],)
38             pie.render('templates/happy.html')
39             a=render_template('happy.html')
40         
41             bar = charts.Line()
42             bar.add_xaxis(df['学期'].tolist())
43             bar.add_yaxis("语文", df['语文'].tolist(),
44 markline_opts=opts.MarkLineOpts(data=[opts.MarkLineItem(type_="average")]),
45    markpoint_opts=opts.MarkPointOpts(data=[opts.MarkPointItem(type_="max"),
46                                          opts.MarkPointItem(type_="min")]))
47             bar.add_yaxis("数学", df['数学'].tolist())
48             bar.add_yaxis("英语", df['英语'].tolist())
49             bar.render('templates/happy1.html')
50             b=render_template('happy1.html')
51             return a + b
52     return redirect(url_for('page1'))
53  
54 app.run(host="0.0.0.0", port="8088")

少儿Python编程_第十八讲 搭建网站

上一讲学习了编写网页代码的方法,到目前为止,创建的网页文件只能用浏览器打开。如果需要用同一网络中的其它电脑或者手机访问该页面,则需要搭建HTTP服务。

普通电脑上也可以搭建HTTP服务,成为小型的HTTP服务器,使用Python搭建HTTP服务非常简单,不需要额外安装软件,只要安装Python的三方模块Flask即可实现。

使用Python开发网站,只需要加入少量代码,就可以将Python的工作成果快速地展示给用户。

18.1 简单例程

Flask是一个轻量级的Web应用框架,占用资源少,使用简单。本节将学习如何用Flask创建一个最简单的网站。

在Anaconda安装时已经安装了Flask,因此可以直接使用,程序代码如下:

01 from flask import Flask
02  
03 app = Flask(__name__)
04  
05 @app.route('/test.html')
06 def hello_world():
07     return '<h1>Hello World! </h1>'
08  
09   app.run(host='0.0.0.0', port=8088)

第01行引入了flask三方模块的Flask类。
第03行创建一个flask对象,并赋值给app,传入的参数name(注意:前后都是两条下划线)是当前模块的名字。
第05行用于指定在访问网址的路径“/test.html”时调用的函数。
第06-07行定义访问路径对应的函数hello_word(),函数返回的字符串”<h1>Hello World!</h1>”是html风格的简单网页数据,其作用是将字符串“Hello World!”作为标题显示。
此处是本节的重点,程序定义了hello_word函数,但并没有看到调用它的代码,这是由于第05行将其下面定义的函数关联到该网站的“/test.html”路径下,也就是说当用户访问该网址时,hello_world()函数被调用,其返回值被返回给浏览器显示。
第09行用run函数开启了Web服务的主循环,它将一直运行,直到程序退出,参数将主机host设置为IP地址’0.0.0.0’,启动程序的端口为8088。’0.0.0.0’是一个特殊的IP地址,设置之后,网络上的其它设备才能访问该服务,否则只有本机可以访问。

在Jupyter Notebook中运行服务后,程序将一直处于运行状态,如果想停止该服务,需要点击Jupyter界面上的“中断服务”(“运行”图标右边的黑色矩形图标),重启服务时也需要先中断,再开启,这点非常重要。否则修改可能不起作用。

程序只使用了不到10行代码,在本机的8088端口启动了HTTP服务,此时用浏览器打开网址:http://127.0.0.1: 8088/test.html,即可看到本机启动的网络服务。其中127.0.0.1 是一个特殊的IP地址,它代表当前计算机。

利用本机对外的IP地址,可以让同一网络上的其他计算机或者手机访问当前的HTTP服务,方法如下,先打开Windows命令行:开始菜单->所有程序->附件->命令提示符,在其中输入ipconfig命令,其结果中显示的IPv4地址(如:192.168.1.107),即本机的IP地址。

通过手机浏览器打开当前HTTP服务的效果如图18.1所示:

图18.1 手机打开Web服务效果

18.2 地址和端口

18.2.1 地址

网页是使用上一讲介绍的工具制作的HTML文件,可通过浏览器解析成图文格式。网站指的是互联网上特定内容相关网页的集合。

浏览网页时,在浏览器上方的地址栏输入网址,一般用英文字母表示。此处的网址指的是URL统一资源定位符,一般由三部分组成:第一部分是协议(如HTTP);第二部分是存有该资源的主机地址,有时也包括端口号;第三部分是主机资源的具体路径。例如:

https://blog.csdn.net/xieyan0811 其中https是协议,blog.csdn.net是主机地址,xieyan0811是主机资源的具体路径。

主机地址可以用IP地址表示,例如192.168.0.1,为了方便记忆,采用域名来代替IP地址标识站点地址,如blog.csdn.net,域名一般由有意义的字符串表示。域名解析就是域名到IP地址的转换过程。域名的解析工作由DNS服务器完成。DNS服务器一般是由运营商负责维护的,它也是互联网的重要组成部分。

打开Windows命令行:开始菜单->所有程序->附件->命令提示符,在其中输入ipconfig命令,其结果中显示的IPv4地址,即本机的IP地址。

18.2.2 端口号

客户端可以通过ip地址或者域名找到对应的服务器,服务器端则可以提供一种或者多种服务,比如Web服务、文件传输服务、邮件服务等等,不同的服务使用端口号区分,例如:邮件服务常用110端口,文件传输常用21端口,HTTP常用80端口等等。端口号的取值范围是1-65535,1-1023为系统端口,其中大多数端口号已经定义了对应的功能,如上面列出的常用端口;1024-5000为临时端口,5001-65535用于自定义端口,开发者开发的服务一般使用这一端口范围。

上例中使用Flask建立的Web服务默认启动在5000端口,而程序用port参数指定了8088为服务启动的端口号。在浏览器的地址栏中输入网址时,用冒号分隔IP地址和端口号,形如http://192.168.1.107:8088/test.html

18.2.3 URL命名规则

URL请求允许使用小写字母,数字,部分特殊符号(非制表符)组成。其中的中文空格等特殊字符需要转码成特殊字符。因此,请尽量减少使用中文以及特殊符号,以使用字母、数字下划线为主。

18.3 动态网页

18.3.1 网页模板

上例中服务端返回的简单网页是由程序生成的,网页内容被写在Python代码文件之中,当网页内容较多时,一般存储在单独的文件之中。

网页常常是由较多的静态内容和较少的动态内容共同构成的,使用模板用于组合静态内容和动态内容。

模板是一个包含响应文本的文件,它通常是html文件,该文件中允许包含“占位变量”来表示动态的内容,"占位变量"在程序中被真实的值所替换。Flask内部使用 Jinja2 模板引擎实现模板功能。从模板文件中读出数据,用真实数据替代占位变量,并将文件中的数据转换成Python字符串,这一过程称为渲染render。

Flask中的模板文件保存在templates目录下,该目录与源码存储在同一目录之中。

模板中的“占位变量”用两个大括号{{占位变量名}}表示,例如:

01 用户名:{{name}}

其中的name将在渲染时被程序中的真实值代替。

18.3.2 生成动态网页

本例用于生成一个动态网页,网页中的大部分数据保存在templates目录下,名为demo.html的HTML文件中。以Jupyter Notebook编辑器为例。

首先,创建目录templates:在文件列表界面的右上点击:New->Folder创建目录,选中该目录(在目录名前的方框中打勾),点左上角的rename将目录名改为templates。

然后,创建网页文件:进入templates目录,点击右上:New->Text File创建文本文件,写入以下HTML格式文本,然后在列表界面,选中该文件,点左上角的rename将文件改名为demo.html。在Jupyter中,HTML文件不能像Python其它文件那样通过点击直接打开,需要先选中该文件,然后点击上方的编辑铵钮Edit,才能修改,直接点击HTML文件,会在浏览器中显示该网页效果。将demo.html修改成以下内容:

01 <html>
02     <body>
03 用户名:{{name}}
04         </br>
05 密码:{{password}}
06     </body>
07 </html>

第03和05行,分别使用了两个占位变量,用于插入动态数据。

在与templates目录平级的位置(不在templates目录之中)创建Python代码文件,输入以下代码:

01 from flask import Flask
02 from flask import render_template
03  
04 app = Flask(__name__)
05  
06 @app.route('/show.html')
07 def page2():
08 return render_template('demo.html', name="张三", password="123456")
09  
10 app.run(host='0.0.0.0', port=8088)

第02行导入了用于渲染网页的三方库render_template。
第06行指定在访问网站的show.html路径时,调用page2函数。
第07-08行实现了page2函数,使用render_template渲染上面编辑的网页demo.html(程序在templates目录下读取文件),然后设置了文件中的两个占位变量name和password。此处涉及的文件目录较为复杂,请读者在计算机上完成以上实验。

程序运行结果如图18.2所示,可以看到网页中的占位变量被程序中设置的参数所代替。

图18.2 利用模板生成网页效果

课后练习:(练习答案见本讲最后的小结部分)
练习一:将本节中的动态网页示例程序输入计算机,保证程序正常运行。
(练习中涉及的内容较多,实现过程中需要不断在网页编辑界面、程序界面、浏览器测试效果的界面之间切换,它锻炼了切分问题,以及分步解决问题的能力。)

18.4 表单

表单form是一种网页的形式,一般用于收集用户信息,例如:网站的用户注册页面一般需要输入用户名、密码、联系方式、真实姓名等信息,此类网页一般由表单实现。

18.4.1 POST与GET方式

POST和GET是HTTP请求的两种方式,上面学习的例程都是GET方式,且客户端没有向服务端传送参数。POST请求和GET请求都支持客户端向服务端传送数据,但格式不同。

1.GET方式

GET方式传递参数时,名/值对是在GET请求的URL中发送的,例如:

01 http://192.168.1.104/login.html?user=a&passwd=123

其中问号之后是客户端向服务端传递的参数,本例中共有两个参数,参数之间用“&”符号分隔,参数是名/值对,如第一个参数的参数名是user,值是a,名值之间用“=”连接。

2.POST方式

POST方式传递参数时,名/值对是在HTTP的消息体中发送的,从URL中无法得知,POST请求更加安全,例如用POST方式传送的密码不会被显示在网页地址栏中,有更好的保密性。下面介绍的表单主要使用POST方式传输数据。

18.4.2 表单

表单是客户端提交给服务器端的一组数据,与之前学习过的软件界面一样,它可以包含输入框、单选框、密码框等等控件供用户输入,一般包含提交和重置两个按钮,当用户点击提交按钮时,浏览器将向服务端发起请求,将表单中用户输入的数据发送给服务器。因此使用表单一方面需要在HTML文件中添加表单,另一方面需要在服务端的程序中处理由表单传来的数据。

首先,使用以下程序在模板目录下创建含有表单的HTML文件login_base.html:

01 <html>
02     <body>
03         <form action="show.html" method="post">
04             用户名:<input type="text" name="name" value="zhangsan"/>
05             密码:<input type="password" name="passwd" />
06             <input type="submit" value="登录"/>
07         </form>
08     </body>
09 </html>

第03行标记了表单form元素的开始,并使用action属性设置当用户点击提交时,跳转到网站的show.html路径,处理方式是POST。
第04行显示了文字“用户名”和普通输入框,表单中的元素由input标签定义,标签的具体类型由其type属性指定,普通输入框的类型是“text”,name设置了被提交数据的名字“name”,以便于服务端的程序读取不同的用户输入内容,属性value指定了输入框的默认值为“zhangsan”。
第05行显示了文字“密码”和密码输入框,它的类型为password,密码输入框中输入的任何字符都显示成“*”以便于保密,name设置了提交数据的名字“passwd”,供服务器读出数据时使用。
第06行加入提交按钮,它的类型为submit,意思是提交,value指定了铵钮上显示的文字是“登录”。
第07行的</form>标签标记了表单结束。

然后,编写Python程序,该程序包含两个界面,一个是提供给用户输入用户名和密码的登录界面login.html,另一个是显示用户是否登录成功的提示界面show.html。

01 from flask import Flask,request
02 from flask import render_template
03  
04 app = Flask(__name__)
05  
06 @app.route("/login.html")
07 def page1():
08     return render_template('login_base.html')
09                            
10 @app.route('/show.html',methods=["POST"])
11 def page2():
12     if request.method=='POST':
13         u=request.form['name']
14         p=request.form['passwd']
15         if u == 'zhangsan' and p == '123456':
16             return render_template('demo.html', name=u, password=p)
17         else:
18             return "用户名或密码错误"
19     else:
20         return "请求错误"
21  
22 app.run(host='0.0.0.0', port=8088)

第01行引入了flask三方模块的Flask和request,其中request用于接收客户端传来的参数。
第06行关联了login.html与page1函数,当用户在浏览器打开网络路径login.html时调用page1函数,route译为路由,它的含义是寻找从源地址到目标地址的最佳路径。
第07-08行实现了page1函数,它从templates模板目录下加载了login_base.html文件,并将其转换成字符串类型,作为page1函数的返回值。

第10行关联了show.html与page2函数,并用参数methods指出接收POST请求发来的数据。
第11-18行实现了page2函数。
第12行判断用户请求是否为POST请求,如果不是POST请求,则跳转到19-20行返回请求错误。
第13行从post请求中取出名为“name”的数据并将该数据赋值给变量u,关键字“name”在HTML文件中定义。
第14行从post请求中取出名为“passwd”的数据并将该数据赋值给变量p。
第15行判断用户名和密码,如果是zhangsan和123456则执行16行,否则返回“用户名密码错误”。
第16行读取之前创建的模板文件demo.html,并用真实的用户名和密码替换HTML文件中的占位变量。

程序运行结果如图18.3所示:

图18.3 登录界面效果图

课后练习:

练习二:在7777端口打开HTTP服务,实现用户注册界面,用户输入:姓名、用户名、密码、年龄,按确认后,显示注册成功界面其中包含用户注册信息。

18.5 思维训练

18.5.1 建立框架

建立处理问题的统一框架,类似于前几讲提到过的抽象的处理问题,它几乎是最重要的学习方法,通过一次或几次学习,总结出处理一类问题的解决方法。以后再遇到类似问题,不需要重新学习具体处理方法,直接代入框架,即可解决问题。人工智能中的“训练机器学习模型”就是建立框架的过程;在程序中使用函数,也用到建立框架的思路,具体方法是:

第一步:切分,将整体功能切分成小块。
第二步:实现,将具体实现功能的代码封装到函数之中,建立最基本的结构,确定框架中的不变部分和可变部分。
第三步:定义使用场景,在什么情况下可以使用,以及如何使用。
第四步:包容,扩展其功能,增加适用范围,让该框架不仅可用于当前情况,之后还可以在更多的情况下使用。

18.5.2 积累

如果找不到规律生成统一框架,就需要记忆具体实例,即积累。但是使用这些未经处理的数据代价很大,需要大量的记忆空间。此时可以考虑简化和分解。

简化时需要区分和保留实例中的重要特征,去掉不重要的,以及常识性的知识。

而分解则是化整为零。写程序也同样有一些约定俗成的要求,比如一个函数中的代码长度最好不要超过一屏,单个代码文件也不要太长,这并不是由于机器无法运行,而是让程序员阅读起来更加方便。因此,有时候即使多次调用,也会把大段代码拆成函数。

积累的另一个使用场景是保存统一框架以外的特例。如果建立处理所有情况的统一框架,规律将非常复杂。此时,可积累一些特例作为统一框架的补充。需要注意的也是保持积累数据的简洁。

18.5.3 重构

建立框架和积累实例是最常用的方法,如果试用了已有的框架和积累的实例仍无法解决问题,可以尝试重构,重构的核心是使用新的角度把简化问题,而不是改进具体的方法。重构的方法有很多,如:

  • 从思考问题的结构转为思考问题的功能,如果目标是出一本校刊,又实在无法画好其中的插画,是否可以使用其它途径,比如从网上下载模板……
  • 把问题划分成小块,然后区分其中重要和次要的成份。重组重要特征,尝试不同的划分方法,不同的边界可能预示着不同解决方法。
  • 调整看问题角度,从整体到部分,比如可以把大问题拆分成多个小问题,再逐一寻找解法;或者把问题放入一个更大的框架。
  • 使用类比,并借鉴类似问题的解决方法,比如将学习语文的方法代入英语学习之中,虽然细节有所不同,但其中一些技巧仍可以正常工作。
  • 头脑风暴,和小组的其他成员在不受任何限制的气氛中讨论、座谈,打破常规,积极思考,畅所欲言,充分发表看法,拼接扩展思路。

18.6 小结

18.6.1单词

本讲需要掌握的英文单词如表18.1所示。

表18.1本讲需要掌握的英文单词

18.6.2 习题答案

  1. 练习一:将本节中的动态网页示例程序输入计算机,保证程序正常运行。
  2. 练习二:在7777端口打开HTTP服务,实现用户注册界面,用户输入:姓名、用户名、密码、年龄,按确认后,显示注册成功界面其中包含用户注册信息。
01 from flask import Flask,request
02 from flask import render_template
03  
04 app=Flask(__name__)
05  
06 @app.route("/login.html")
07 def page1():
08     return render_template('login.html')
09  
10 @app.route('/show.html',methods=["POST"])
11 def page2():
12     if request.method=='POST':
13         u=request.form['name1']
14         p=request.form['mima']
15         l=request.form['name2']
16         w=request.form['old']
17         iiii="注册成功,用户名:"+u+",密码:"+p+", 姓名:"+l+", 年龄:"+w
18         return iiii
19     else:
20         return "不是post, 需要post"
21

少儿Python编程_第十七讲 互联网和Web服务

现在人们每天都在使用网络,交通、住宿、购物、外出吃饭大多数都用手机操作,甚至很多人出门都不带钱包。如果家里断网,或者手机断网,那么用微信、看新闻、看视频、网购、手机支付都将无法使用。

网络到底是什么?每一台手机、电脑、以及远程的服务又是如何连接?如何传输数据?如何开发自己的网站,需要哪些技术?本讲将一一为读者解答。

17.1 互联网

早期接入网络的只有计算机,所以称为计算机网络,后来又有手机、智能硬件加入,称之为互联网(英文Internet,也译为因特网)更加准确。它是由多个小网络连接而成的庞大网络,在硬件方面,网络之间通过网络设备(交换机、路由器等)以及链路(无线链路、光纤等)相连;在软件方面通过网络协议通讯。

17.1.1 硬件连接

网络硬件连接如图17.1所示:

图17.1 网络硬件连接示意图

在家里或者单位上网时一般通过路由器连接电脑(或手机设备)和网络,目前的路由器一般同时提供有线和无线连接两种方式。有线连接是通过网线连接路由器和其它设备,无线连接则使用WIFI连接设备和路由器。相比之下,有线连接速度更快,数据传输更稳定,而无线连接更加方便。普通计算机与路由器之间一般使用网线相连,而手机与家中路由器一般使用无线连接。

路由器是本地网络和互联网之间的枢纽。路由器一方面构建小型的网络用于连接本地设备,另一方面向外连接互联网。除了计算机,通过路由器连接的还有笔记本电脑,智能硬件,如智能音箱、网络摄像头等,从而使物与物连接,通过协议协同工作,也是常说的物联网。

在户外或者不连接路由器的情况下,手机还可以通过移动网络上网,手机利用无线传输连接基站,基站又接入互联网。基站的全称是公用移动通信基站,是移动设备接入互联网的接口设备。

服务器是向外提供服务的设备,服务器是由高性能的计算机或者大型计算机组成的系统,相对于普通计算机性能更好,更稳定。根据功能不同,可支持数据库服务、文件服务(网盘)、应用服务(微信、淘宝)、WEB服务(百度、新浪)等等。手机和电脑通过网络与服务器连接。

17.1.2 软件支持

互联网上的数据通过协议传输,协议本身不是一种软件,而是一种通讯标准,它如同人类的语言,在不同的设备、不同的软件之间,只要服从同一套协议,即可相互传输数据、交换信息。网络协议种类繁多,协议常被分层,下层协议为上层协议提供服务,层层包裹。根据不同的标准,有的分为五层,有的分为七层。

下面介绍比较简单的TCP/IP四层网络结构,如图17.2所示:

图17.2 TCP/IP网络结构

1. 链路层
最底层的“链路层”负责设备与网络之间的数据交换,在这一层实现了对不同网络(有线网、无线网)的支持。

2. 网络层
网络层用于在复杂的网络环境中为数据报找到一个合适的传输路径,这一层实现了IP协议。 IP****地址是给每个连接在互联网上的主机或路由器分配的一个地址,用于标识网络中的唯一一台设备。32位地址可用四个字节表示,通常将每一个字节换算成一个十进制数,每个字节的数值范围在0-255之间,各字节之间用“.”分隔,IP地址形如“192.168.0.1”。

3. 传输层
传输层实现了两台设备之间的数据传输,支持TCP和UDP两种连接方式,TCP协议的工作方式是:建立连接、传输数据、断开连接,相对来说更可靠。而UDP也叫无连接协议。程序员常常在传输层之上编写基于TCP或UPD协议的程序。

4. 应用层
最上层是应用层,这一层用于支持针对具体功能的协议,如HTTP(超文本链接协议),FTP(文件传输协议),TELNET(虚拟终端协议等)。像浏览器和Web服务器就通过HTTP协议通讯。

综上,网络协议中的每一层都需要它下层的支持。层层封装,最终实现数据传输功能。

17.2 Web服务

WEB服务也是最常见的一种服务,它实现网上信息浏览服务,也就是说无论是手机或是电脑,使用浏览器连接网站所获得的服务都属于WEB服务。Web服务器一般指网站服务器。

17.2.1 HTTP 协议

HTTP协议是最常见的网络协议,它用于客户端(手机或电脑)的浏览器与服务器提供的WEB服务的交互。HTTP是应用层协议,是简单的请求-响应协议,它基于TCP连接。

工作流程如下:用户使用电脑打开浏览器,在其地址栏输入http://www.baidu.com,浏览器先在应用层将其按HTTP协议规则编码,然后在传输层封装成符合TCP规则的数据包,接下来在网络层进行IP规则封装,最后编码成链路层可正常传输的数据包,将数据传输至互联网,在传输层通过IP协议查找和定位百度服务器,找到后在本机与服务器之间建立TCP连接,进行HTTP协议数据包的传输,在数据交互完成之后断开连接。电脑的浏览器收到数据、解析内容,并将其中的文字和图片显示在浏览器中。

客户端与服务器交互一般有两种方式:B/S模式和C/S模式。其中的B代表Browser浏览器,C代表Client客户端,S代表服务器端,二者的不同在于, C/S模式需要在本机安装软件后才能使用,例如微信,而B/S模式使用本机的浏览器就能访问,不用另外安装软件,比较方便。

当开发者编写了一段程序或者功能,需要提供给用户使用,尤其是提供给网络上其它计算机或者手机上的用户使用时,B/S模式是一个很好的选择。开发者可以将自己的计算机作为小型的服务器,在其上运行WEB服务,供他人通过浏览器、本地网络、HTTP协议使用该功能。

17.2.2 HTML语言

HTML是超文本标记语言的缩写,用于创建网页,在浏览器上看到的网页大多数都是由HTML语言编写的。

HTML语言编写的网页也存储在文件之中,扩展名一般是“.html”或者“.htm”。手动编写html文件难免输入错误,建议使用以下网址提供的HTML编辑工具:https://c.runoob.com/front-end/61,编写和验证HTML,验证无误后再使用。

先来看一段最简单的HTML代码:

01 <html>
02   <head>
03     <title>我的标题</title>
04   </head>
05   <body>
06     <h1>一级标题</h1>
07     <p>正文</p>
08   </body>
09 </html>

HTML标签是由尖括号括起来的关键词,比如<p>是一个标签; <p>正文</p>是一个元素,也就是说元素由开始标签、结束标签以及其中的内容组成。

标签有以下几种常用写法:

1.包含开始标签和结束标签的内容

大多数的元素使用开始标签和结束标签,标签成对出现,它的格式为:

01 <标签>内容</标签>

例如:

01 <p>内容</p>

标签p用于定义段落,<p>和</p>分别设置了元素的起始点和结束点,以上语句定义了内容是“内容”的一个段落。

2. 空元素标签

空元素标签是只有标签,没有内容,它的格式为:

01 <标签/>

例如:

01 <br/>

标签br用于换行,不显示任何信息,使用空标签即可实现该功能。

3. 带属性的标签

在标签中设置属性的格式为:

01 <标签 属性名=值>内容</标签>
02 <标签 属性名=值/>

例如:

01 <a href="http://www.baidu.com ">打开百度</a>
02 <img src="http://pics.sc.chinaz.com/Files/pic/icons128/6519/r16.png”/>

第01行标签a用于超链接,在网页上显示“打开百度”,当点击该字符串时,网页跳转到由属性href指定的网页地址:http://www.baidu.com。在定义这一网页元素时,即需要在网页中显示字符串,又需要指定跳转的位置,带属性的标签可实现该功能。

第02行标签img用于显示图片,网页中显示的图片必须存储在网络上,并使用src属性设置图片的地址。

4. 注释

程序注释是对代码的解释和说明,目的是为了让自己和其他程序员更容易看懂,不需要显示给用户。

HTML中的注释格式为:

01 <!—注释内容-->

例如:

01 <!—这是一个注释-->

5. 网页的基本元素

一般网页中可以使用嵌套,其中的元素层层包含,元素通过标签定义。一般网页都会包含html、head、body这几个基本元素,如上例所示:

第01和09行为html标签,在最外层,用于标记网页的开始和结束。

第02和04行为head标签,是文件头,head中的内容一般不被显示出来,用于描述网页的字符编码、网页的风格,有时还包含一些可运行的程序。

第05和08行为body标签,是网页的主体,通过浏览器显示的内容都在body中添加。

网页中的文字、段落、输入框、按钮、图片、表格都对应不同的标签,读者如果想学习更多相关知识,请参考:https://www.runoob.com/html/html-tutorial.html

开发者一般不需要手写每一行HTML代码,但需要能看懂基本的HTML格式文件。

如果读者比较熟悉Word软件,也可以在Word中编辑网页内容,然后另存为“网页(*.html)”格式,以此创建html文件,美中不足是使用Word创建的网页文件内容较多,难以阅读,但可以正常使用。

课后练习:(练习答案见本讲最后的小结部分)

练习一:用自己的语言解释以下概念:互联网、网址、网页。

练习二:在https://c.runoob.com/front-end/61中编辑和调试,生成如图17.3的网页,并保存在HTML文件中,在本机的浏览器中打开。

图17.3 网页效果

17.3 网站开发相关知识

17.3.1 客户端和服务端

服务端用于给其它机器提供服务,例如:百度搜索、腾讯视频等功能都是由远程服务器提供的,相对的,用户使用手机或者电脑连接服务器时称为客户端。

当使用Jupyter Notebook时,可以看到弹出一个类似命令行界面的黑框,它就是启动在后台的服务端,同时弹出的浏览器是客户端,客户端与服务端连接,此时可以用浏览器调试程序,实际上客户端只负责显示,Python代码和数据都保存在服务端,当关闭服务端后(黑框),客户端也无法正常使用。

17.3.2 前端和后端

网站开发通常分为前端开发和后端开发,前端开发主要关注与用户的交互部分,比如文字、图片、音视频的显示,支持网页内容在计算机和手机的屏幕中不同的版式,处理用户在网页上的操作等等。

而后端主要用于支持网页对应的功能,比如搭建各种服务,管理多台服务器协同工作,从数据库中读取和存储数据,计算、预测、分析筛选等等,后端往往是用户不可见的。

前端和后端使用不同的语言开发,本讲主要介绍前端的实现方法,在下一讲将介绍后端的实现方法。

17.3.3 网页和网站

网页是上例中使用HTML语言编写的文本文件,可以用浏览器打开。比如淘宝中的每一个页面都是网页,如淘宝首页、商品列表、详细介绍都以网页方式呈现。网页相互之间通过超链接等方式跳转(从一个网页打开另一个网页)。

网页是网站的重要组成部分,比如淘宝网是一个网站,它包括众多网页,网页是网站的前端部分,再加上后端存储、计算等等后台支持,共同构成了网站。

17.3.4 静态网页和动态网页

网页又分为:静态网页和动态网页,静态网页是事先写好,一般以HTML格式存放在服务器上。如果想修改其内容,则需要修改编辑HTML文件。而动态网页根据用户的操作生成其内容,比如搜索网页根据用户搜索的内容返回不同列表,新闻网页根据当前的新闻数据的变化不断更新内容,浏览器中显示的HTML格式的数据是根据当时的数据以及用户的需求即时生成的。HTML格式的数据常由其它编程语言自动生成,像Java、PHP都是常用的开发工具,Python也是常用工具之一,它最大的优势是使用简单,下一讲将介绍用Python生成动态网页的实现方法。

17.3.5 网页相关编程语言

除了基本的HTML语言以外,CSS和JavaScript也是前端开发的必备技能。

CSS用于精确控制网页的排版,比如一个网站中的网页一般具有同样的字体、背景颜色、显示风格等等,如果在每个网页的每个控件中逐一设置,网页数据将变得非常庞大而复杂。CSS用于描述HTML中组件的样式,只需要在HTML的头部(head)中指定css文件,即可在网页的各个控件中使用CSS中定义的风格。

JavaScript是一种脚本语言,它也支持变量、表达式、函数等等。一般嵌入在网页之中,在浏览器显示网页时,由浏览器解释执行,如果把HTML称为网页的描述语言,则可以把JavaScript称为网页编程语言。它可以给HTML增加动态的功能,比如接收网页中按钮按下的事件并调用对应的功能。

17.3.6 HTML5

HTML5是HTML的第五次修改版本。它增加了更多的元素和属性,实现了很多之前只能通过嵌入JavaScript脚本才能实现的功能,比如视频元素、音频元素、更强大的表单功能等等。

需要注意的是:一些早期的浏览器,或者浏览器早期版本,无法正常支持HTML5,所以使用HTML5编写网页时需要考虑浏览器是否支持。

17.4 思维训练

17.4.1学习的能力

同样的学校,同样的老师,一样做作业,为什么学习效果却各不相同?除了努力程度,也要看能力。人们常把能力归因于先天的基因和后天的教育。

人与人之间基因的相似程度高达99.99%。在开发机器人的时候,科学家们发现:走路、抓握、视觉、语言比逻辑推理、数学更加复杂,而人类无论聪明与否都能正常使用这些功能。可见,实际上普通人的智力差异并没有想象中那么大。有些基因只有特定情况下才能开启,没努力到一定程度,就无法开启相应的技能。

能力也与知识基础相关。有时,同一个人在不同阶段做同一件事效果也有差异。两年前我第一次看一本强人工智能的书,每天看两小时,近一个月才看完,不是没有充足的时间,主要因为其中不熟悉的概念太多,看多了也吸收不了。今年,当这本书看到第四遍的时候,三五天时间就可以看完,随着一次一次复习,里面很多东西慢慢记住了。就像建金字塔一样,很多时候取决于基础。

整体的能力由很多更小的能力组合而成。有些人从小学习了某些技能,经年累月逐渐变成常识和习惯,时间太长,以至于我们以为天生就会。人们常把举一反三的看作是与生俱来的能力。以写程序为例:如果不理解每一条语句,更不能理解它们组合之后的功能,如果面临考试,只能死记硬背,之后也只能解决完全相同的问题。而这种泛化能力的差异,都是由于前期偷懒、不求甚解导致的。

偷懒在很多时候并不是故意的,只是一种习惯。大多数抉择并不是基于深思熟虑,而是取决于习惯。观察实践的习惯,坚持认真的习惯、列计划、复习、定期自查、整理思路、排列优先级,这些方法在一次又一次地重复之后,构建了脑中的回路,最终铸就了性格。决定着面对每一次受挫、每一次走神,每一个诱惑、每一个问题时的反应。日积月累,人与人之间的差别也越来越大。

好在,习惯可以后天塑造,但是需要较长的时间周期,同理,坏习惯养成的时间越长,就越不容易改变。

17.4.2 知识屏蔽

到目前为止,我们学习了游戏制作、简单的数据库、数据分析、网络编程……实际上,深入学习其中的任何一项都需要大量时间。比如在大学阶段的《计算机网络》课,学习网络相关的知识、原理,使用方法,这门课程需要学习整个学期。如果要系统地学习上述知识,需要用大学四年时间学习计算机相关专业。然而,很多深层知识在工作中也很少用到。笔者利用多年软件开发和数据分析的工作经验,整理了其中最为重要的知识点。

尽管无法用一本书讲完所有相关的计算机知识,花几个月的时间,也不能把一个四年级小学生培养成直接去IT公司面试和工作的员工。选择哪些知识点,深入到什么程度?让大家既能学习到具体实用的技术,又不过于肤浅?这里加入了更多的扩展,并且刻意屏蔽了一些原理和内部细节,讲到够用即可的程度。利用同样的时间精力,别人还在研究原理,你已经写过很多代码了。

同理,也建议大家在小学和中学阶段,不要陷进细节里,尽量扩展宽度,以便从整体的尺度以及更多的角度考虑问题。

17.5 小结

17.5.1单词

本讲需要掌握的英文单词如表17.1所示。

表17.1本讲需要掌握的英文单词

17.5.2 习题答案

  1. 练习一:用自己的语言解释以下概念:互联网、网址、网页。

详见本讲正文部分。

  1. 练习二:在https://c.runoob.com/front-end/61中编辑和调试,生成如图17.1的网页,并存储在HTML文件中,在本机的浏览器中打开。
01 <html>
02   <body>
03 <h1>标题1</h1>
04 <p>我是第一段</p>
05 <p>我是回车</p>
06     <br/>
07 <a href="http://www.baidu.com">这是超链接</a>
08 <p>我是图片</p>
09       <img src="http://pics.sc.chinaz.com/Files/pic/icons128/6519/r16.png"/>
10   </body>
11 </html>

打开Windows记事本(开始->所有程序->附件->记事本),输入以上内容,保存为a.html。在文件管理器中双击打开a.html即可在浏览器中显示此网页。

少儿Python编程_第十六讲:图形界面开发

运行在计算机上的程序一般分为命令行程序和图形界面程序,例如:安装Python三方模块的pip命令,软件版本管理的git命令等都属于命令行程序;而大多数软件使用图形界面,例如Windows的Word,Excel,画图等等软件都是图形化用户界面,简称GUI。

在图形化用户界面中,用户可以用鼠标操作菜单、按钮等图形化组件,并从对话框等图型化组件中获取信息。实现图形化界面的方法与制作游戏界面的流程相似:在初始化工具之后,进入主循环接收用户事件,并且进行显示、反馈等处理,直到程序退出,才结束主循环。与绘制游戏界面不同的是,游戏界面中的绘图、处理鼠标事件都需要开发者写程序自行处理,而图形用户界面内部已经实现了按钮、文本框的绘制和响应事件,使用时调用这些控件即可,减少了编写程序的工作量。

图形界面在任何编程语言中原理都一样,本讲通过Python图形界面编程,介绍图形界面中的基本概念和简单用法:常用控件、布局方法、事件处理。

16.1 图形界面入门

Python的图形用户界面常使用Tkinter开发,Tcl 是“工具控制语言”的缩写。Tk是Tcl“图形工具箱”的扩展,而Tkinter是Tk interface的缩写,意思是TK界面。

在Windows系统中Tkinter已由Anaconda安装,可以直接使用,在Linux下则需要使用apt安装python3-tk软件包。

16.1.1 基本概念

在学习具体编程之前,先了解一些基本概念。

1.控件

控件也叫组件,是图形用户界面中最基本的组成部分,常用的控件有:按钮、文本框、标签、表格等等。

2.容器

容器是一种特殊的控件,它能容纳其它控件,如窗口、对话框都属于容器。

3.布局

布局是控制控件在容器中的大小和位置的方法。

4.事件处理

事件是可以被程序识别的操作,如:按下按钮,选择某个单选按钮或者复选框,关闭程序等等,开发者往往需要对事件做出处理,响应某个事件的函数就是事件处理程序,也被称为回调函数。

16.1.2程序示例

下例是一个简单的图形界面程序,它创建窗口。并在窗口中显示两行文字“test1”和“test2”。

01 import tkinter
02  
03 win = tkinter.Tk()
04 win.geometry("320x240+200+50")
05 tx1 = tkinter.Label(win, text="test1")
06 tx1.pack()
07 tx2 = tkinter.Label(win, text="test2")
08 tx2.pack()
09 win.mainloop()

第01行引入tkinter模块。
第03行创建一个实例,用于显示窗口。
第04行设置窗口大小为:宽度320,高度240,位置在屏幕横坐标200,纵坐标50。
第05行创建标签控件tx1用于显示文字,Label函数有两个参数,第一个参数指定控件所在的容器,第二个参数text指定标签上显示的文字。
第06行将控件放置在容器之中,pack是布局的一种方法,将在之后的“布局”部分详细介绍。
第07-08行创建和放置了第二个标签tx2。
第09行开启主循环,在窗口关闭时主循环退出,程序结束。

程序运行结果如图16.1所示:

16.1 简单的图形用户界面

16.2 布局

布局是把控件放置到容器之中,并且指定放在哪里,以及如何放置。Tkinter有3种基本布局管理器:pack、grid和place,还提供容器Frame支持复杂的嵌套布局。

16.2.1 常用布局方法

1. pack布局

pack是最常用的布局方法——顺序布局,用于按顺序添加各个控件,上例中使用pack分别添加了两个文字标签,可以看到控件按添加的顺序依次显示在窗口中。图16.2分别展示了横向和纵向顺序布局的方法。

图16.2 pack布局示意图

其基本语法如下:

01 控件名.pack(可选参数)

布局的可选参数如表16.1所示:

表16.1 布局参数表

2.grid布局

grid按网格摆放控件,如图16.3所示,其中每个控件的位置都由行索引row和列索引colomn两个值确定,索引号从0开始(不是1),如左上角的控件1行列为0,0;控件2行列为0,1,以此类推。

图16.3 grid布局示意图

其基本语法如下,该函数也支持表16.1中的参数。

01 控件名.grid(row=行索引, column=列索引,可选参数)

3.place布局

place按具体坐标摆放控件。如图16.4所示,用x1,y1设置控件1左上角的位置。

图16.4 place布局示意图

其基本用法如下,该函数也支持表16.1中的参数。

01 控件名.place(x=横坐标, y=纵坐标,可选参数)

16.2.2 容器布局

当界面设计比较复杂时,一般使用Frame容器实现布局。Frame译为框架,它是一种容器,容器是可以包含其它控件的特殊控件。图16.5在同一窗口中加入了11个控件,包含顺序和网格两种布局方法,实现此界面,需要建立两个frame容器,一个容器为深色背景,用于存放控件1和控件2,另一个容器为浅灰色背景,用于存放其它网络布局的控件。Frame本身也是控件,两个frame控件也使用了顺序布局。

图16.5 frame容器示意图

其基本语法如下。

01 f= Frame(父容器,可选参数)

以上程序创建了容器f,之后可以将其它控件加入该容器。“父/子”用于描述容器和控件之间的关系,通常将包含其它控件的容器称为“父”,而被包含的控件被称为“子”。

16.2.3 综合实例

本例中使用了pack、grid、place、frame多种方法布局界面。

01 import tkinter
02  
03 win = tkinter.Tk()
04 win.geometry("320x240+200+50")
05  
06 f1 = tkinter.Frame(win)
07 f1.pack()
08 f2 = tkinter.Frame(win)
09 f2.pack()
10  
11 tx1 = tkinter.Label(f1, text="test1")
12 tx1.grid(row=0,column=0)
13 tx2 = tkinter.Label(f1, text="test2")
14 tx2.grid(row=1,column=1)
15 tx3 = tkinter.Label(f2, text="test3")
16 tx3.pack()
17 tx4 = tkinter.Label(win, text="test4")
18 tx4.place(x=10,y=10)
19  
20 win.mainloop()

第01-04行用于引入模块和创建窗口。
第06行创建容器f1,并指定其父容器为窗口。
第07行用pack方法将容器以顺序方式布局。
第08-09行建立并加入了第二个容器f2。
第11行创建标签控件tx1,设置其父容器为f1。
第12行用网格方式布局tx1显示在网格的第0行0列。
第13-14行创建标签控件tx2,并以网格方式布局tx2显示在网格的第1行1列。
第15行创建标签tx3,设置其父容器为f2。
第16行用顺序方式将控件tx3布局到其父容器中。
第17行创建标签tx4,设置其父容器为窗口win。
第18行用指定具体位置的方式将控件布局到窗口的坐标为(10,10)位置上。
第20行开启主循环,在窗口关闭时主循环退出,程序结束。

程序运行结果如图16.7所示,其中深灰色部分为容器f2,浅灰色部分为容器f1,它们大小不同是由于容器大小等于其子控件大小。f1中子控件更多,因此区域更大。

图16.6 布局综合实例运行结果

16.3 控件

Tkinter除了标签控件Label,还支持很多其它控件,本节将介绍最为常用的:按钮、输入框、选择框、以及显示图片的控件。

16.3.1 常用控件

1.标签

标签控件用于显示文字或者图片,定义方法如下:

01 tkinter.Label(父容器, [可选参数])

控件常用的可选参数如表16.2所示:

表16.2 控件常用参数

2.按钮

按钮控件是最常用的控件,例如对话框中的“确定”、“取消”都用按钮控件实现。定义方法如下:

01 tkinter.Button(父容器, [可选参数])

3.输入框

输入框显示为矩形框,供用户输入信息使用。定义方法如下:

01 tkinter.Entry(父容器, [可选参数])

4.选择框

一般情况下,选择框前面是一个矩形方框,后面跟随说明文字,例如:让用户选择“婚否”,结婚则在矩形方框中打钩,否则留空。定义方法如下:

01 tkinter.Checkbutton(父容器, [可选参数])

5.图片

图片不直接作为控件使用,而是作为标签或者其它控件的背景,如果不设置标签文字,只设置其背景图片,则该标签是一个图片标签。图片的加载方法如下:

01 tkinter.PhotoImage(file=图片路径)

图片加载后,可放在控件的可选参数image中使用。

16.3.2 获取和设置控件的属性

属性指的是控件的性质,一般在创建控件时指定,如:控件的宽度width,高度height等,查看控件的属性方法类似于访问字典,具体方法如下:

01 控件变量名[属性名]

使用configure方法可以重新设置控件属性值,使用方法如下:

01 控件变量名.configure(属性名=属性值)

下例是操作属性的实际应用:

01 x = tkinter.Label(win, text=”abcd”)
02 print(x[‘text’])
03 x.configure(text=’efg’)

第01行建立了标签控件,并设置标签显示的文字:text属性为“abcd”。
第02行显示出控件变量x的text属性。
第03行修改控件变量x的text属性为“efg”。

16.3.3 综合实例

下面通过综合实例,进一步巩固本节中介绍的各个控件的用法。

01 import tkinter
02  
03 win = tkinter.Tk()
04 label = tkinter.Label(win,text="请填表") # 创建文字标签控件
05 label.pack()
06 img = tkinter.PhotoImage(file='bird.png') # 加载图片
07 label_img = tkinter.Label(win,image=img) # 创建图片标签控件
08 label_img.pack()
09 entry = tkinter.Entry(win) # 创建输入框控件
10 entry.pack()
11 check = tkinter.Checkbutton(win,text="婚否") # 创建选择框控件
12 check.pack(anchor='w')
13 button = tkinter.Button(win, text="退出") # 创建按钮控件
14 button.pack()
15 win.mainloop()

程序运行结果如图16.7所示:

16.7 控件综合实例运行结果

课后练习:(练习答案见本讲最后的小结部分)

练习一:绘制如图16.8所示的计算器界面,其中上方用Label显示输入数值和计算结果,下方提供12个按钮用于输入数字和符号。

图16.8 计算器效果图

16.4 事件处理

程序需要接收用户操作,并进行反馈。用户操作和系统发来的信息统称事件,事件又分为两种,一种是与整个窗口相关的事件,比如关闭窗口,另一种是与单个控件相关的事件,比如按下按钮Button产生的事件。

16.4.1 控件事件处理

在创建按钮时,可通过command参数设置当按钮按下时调用的函数,即事件响应函数,用法如下例所示:

01 def do_1():
02     print("按下1")
03  
04 bt=tkinter.Button(win, text='1',command=do_1)
05 bt.pack()

第01-02行定义了事件的响应函数do_1,并在函数中显示字符串“按下1”。
第04行创建按钮控件,并指定按下按钮时调用函数do_1(注意:本行do_1函数并未被调用)。

16.4.2 窗口事件处理

在创建按钮时,可通过protocol设置窗口相关事件的响应函数。下例为设置窗口关闭事件,在窗口关闭时自动调用fun1函数。

01 import tkinter
02  
03 def func1():
04     print("关闭窗口")
05     win.destroy()
06     
07 win = tkinter.Tk()
08 win.geometry("400x400+200+50")
09 win.protocol("WM_DELETE_WINDOW",func1)
10  
11 win.mainloop()

第03行定义事件响应函数fun1。
第04行显示字符串"关闭窗口"。
第05行调用窗口的destroy方法销毁窗口。
第09行设置在窗口关闭时调用自定义函数fun1,即关联事件和响应函数。

课后练习:

练习二:继续完成上题中计算器程序,响应用户按下各个按钮的事件,更新Label显示算式,在用户按下”=”按钮时,计算算式结果。

(提示:Python的eval函数用于执行字符串表达式,例如eval(“1+2”)的结果为3;十二个按钮功能类似,建议先将其中一两个按钮调试正常后,用复制粘贴的方法实现其它按钮,以免在调试过程中反复修改)。

16.5 思维训练

16.5.1 眼中的世界

人们对客观事物比如什么是一、二、三、花、草、树木有着类似的理解,有了这些共识,可以通过语言来沟通;这也让我们误认为,每个人眼中的世界都是相同的。

然而,“一千个读者眼里有一千个哈姆雷特”,不仅是故事,人们对单个文字的理解也不尽相同。对于什么是“爱”,什么是“道德”,这些并非具体可见的事物,由于文化和经历不同,大家的理解也不尽相同,越是不能用语言描述的感觉,差异可能越大。

为什么有些笑话,只有大人才觉得有趣,因为孩子并不知道很多语言的二义性以及背后的引申含义,艺术家激活了大家拥有的共同体验,它们又往往是不可言喻的。引领着读者的思维在具体文字图像和感觉之间跳跃。

语言是一种抽象的符号,是人们交流的工具,却不是现实或思维本身。任何事物或者词汇的意义都取决于它与其它事物的关系,从而形成了脑中复杂的关系网络,而不是简单的字典上的定义。

16.5.2 用语言思考

在表达的过程中,思维本身也在变化,表达过程中可能创造出一些新的想法,这就是“用语言思考”。对于复杂的内容,无法用语言描述它的所有细节,在表达的过程中,必然经过提炼和简化,这也重构了思维状态。因此,有时候向别人提问的过程中,自己就找到了答案。

语言的结构以链式为主,而思维内部一般是网状连接,描述过程是将一团相互纠缠的细网拆解成为一条主链。当一个人用语言的标号代替一套复杂的结构,就可能建立和处理更加复杂的内容。想要利用语言在他人脑中重建自己脑中的思维结构,必须掌握网状和链状结构相互转换的能力,同时还要了解大家头脑中的“共识”。

比如写一部小说或者电影的观后感就是一种总结和梳理,从文章的内容和结构上也能看到写作者的思路和关注点。练习作文或者写程序,不只是掌握语言本身,也是锻炼总结、抽象的能力。这种能力必须通过不断地书写、修改、总结来增强。

虽然很多思维与语言无关,比如触觉、味觉、情绪,不一定能用语言精确地表达出来,但我们仍然常用语言来思考问题,比如常常听到小孩自言自语,成人思考问题,有时也像在脑中独白或者与人对话,这都是语言赋予我们的思考方式。

16.5.3 语言以外的表达方式

语言是一种链式的表达方式,除了简单,它还有利于推导,归因……但是,脑中的结构往往更加复杂,比如下图中的关系,虽然可以用语言描述,但是非常麻烦。除了各个部件之间的关系,描述时还需要考虑如何遣词造句,这就把问题变得更加复杂。

图16.9 关系图

流程图,思维导图,公式,程序,它们不仅与自然语言的语法不同,结构也不同。在不同情况下,可采用不同的表达方式,如果做数学应用题的时候也用画图的方法,换一种角度表达,可能描述本身就是问题的答案。

16.5.4 学习语言

霍金曾说:多写一个公式就会吓跑一半读者,英国一项研究证明:数学公式不但会吓跑普通读者,科学家也会被公式吓跑。这主要由于日常生活中并不经常使用公式。学习语言需要大量时间。自然语言是这样,公式和程序语言也一样,需要反复学习和使用才能记忆。

脑中没有大量的存储空间用于记忆,即使空间足够,从海量信息之中查找也需要大量时间。因此,只有反复使用的内容才能被记住。也只有掌握了语言,才可能利用它思考和解决问题。学任何一门非母语的语言都有很大难度,甚至大多数人对母语掌握得也没有想象中那么好,比如很少有人能驾驭小说、新闻等不同风格的文章写作。

写作的人将脑中的思维框架转换成文字,并试图在读者脑中构建起类似的结构,其中包括着大量的常识和背景知识,比如通过故事发生的时间、地点、氛围、故事风格,激活读者脑中的某种场景,这些都是文字之外的信息。思维中故事的框架是多层次的网络,而机器所识别的文字只是相对扁平的结构。

通过前几讲的学习可以看到,目前机器学习模仿写武侠小说的能力已经非常强大,而小说的风格明显不适合写新闻。如果想训练机器写所有类型文章,则需要使用非常大量的数据训练模型,让它拥有基本写作能力。然后再根据要生成的不同文章类型,定向训练。机器有海量的存储和算力,但不是每个人都有时间和条件作大规模的训练。

学习自然语言也一样,如果希望读懂新闻,对话,科技论文,就需要非常大量的训练,不如想看论文,就主要读论文,当然,练习“阅读论文”对“对话水平”提高有限。

16.6 小结

16.6.1单词

本讲需要掌握的英文单词如表16.3所示。

表16.3本讲需要掌握的英文单词

16.6.2习题答案

1.练习一:绘制如图16.8所示的计算器界面,其中上方用Label显示输入数值和计算结果,下方提供12个按钮用于输入数字和符号。

2.练习二:继续完成上题中计算器程序,响应用户按下各个按钮的事件,更新Label显示算式,在用户按下”=”按钮时,计算算式结果。

01   import tkinter
02   
03   win=tkinter.Tk()
04   
05   f1=tkinter.Frame(win)
06   f1.pack()
07   f2=tkinter.Frame(win)
08   f2.pack()
09   
10   label=tkinter.Label(f1,text="")
11   label.grid(row=0,column=0)
12   def do_1():
13       y=label['text']
14       x=str(1)
15       s=y+x
16       label.configure(text=s)
17       
18   bt1=tkinter.Button(f2,text='1',command=do_1)
19   bt1.grid(row=1,column=0)
20   def do_2():
21       y=label['text']
22       x=str(2)
23       s=y+x
24       label.configure(text=s)
25   
26   bt1=tkinter.Button(f2,text='2',command=do_2)
27   bt1.grid(row=1,column=1)
28   def do_3():
29       y=label['text']
30       x=str(3)
31       s=y+x
32       label.configure(text=s)
…   # 此处省略其它数字
90   btjia=tkinter.Button(f2,text='+',command=do_jiahao)
92   btjia.grid(row=4,column=1)
93   def do_dengyu():
94       y=label['text']
95       t=str(eval(y))
96       label.configure(text=t)
97       
98   btd=tkinter.Button(f2,text='=',command=do_dengyu)
99   btd.grid(row=4,column=2)
100  def do_jianhao():
101      y=label['text']
102      x=str('-')
103      s=y+x
104      label.configure(text=s)
…    # 此处省略乘除运算
132  win.mainloop()

3.练习三:总结常见错误信息及其原因。

少儿Python编程_第十五讲:图像和声音

上一讲学习了Python游戏开发的简单方法,并在练习中下载和阅读了几个小游戏的源代码。本讲将自己动手制作游戏,练习编写50行左右的比较复杂的程序,在此过程中将继续学习图形图像相关知识、播放声音,以及运用前面学习的各种数据类型、函数等技术。

15.1 图形图像

15.1.1 原理

早期的计算机和手机都用按键输入,屏幕只能显示文字。后来随着软硬件升级,逐步出现彩色显示器,以窗口界面为主,使用鼠标和触摸屏操作的计算机和手机系统。

现在在屏幕上看到的所有显示都是以图片方式“绘制”出来的。之前讲过软件分为系统软件和应用软件,系统软件的一部分工作是管理当前开启的应用程序(应用软件),并将各个软件的输出“绘制”在屏幕上。因此作为普通开发者,只需要考虑应用软件的输出即可。

上一讲在窗口中绘制图形:窗口是开发者在程序内定义的一个固定大小的区域,绘图位置通过坐标(x,y)指定。

屏幕上显示的画面又分为图形和图像两种,之前学习的绘制矩形、圆形,以及显示文字都属于“图形”,另一种是图像,它可能是拍摄的照片或者用画图软件绘制的卡通人物或风景,在Python程序中从文件读出,并将其内容绘制到某一区域,叫做绘制图像。

15.1.2 图像格式

从绘图的角度看,图像分为两种:带有透明度通道的图片和不带有透明度通道的图片。

图15.1 图片透明通道示意图

如图15.1所示,将两张卡通羊图片绘制在背景图上,左侧不带透明通道,因此将其白色背景也贴了出来,右侧带透明通道,并其将卡通羊的背景置为透明,贴图后的效果更加自然。一般情况下,在绘制背景图片,以及后面不需要透出其它图片时,使用不带透明通道的图片即可。而绘制前景图片,比如游戏中需要移动变化的卡通人物,则使用带透明通道图片。

图像一般存储在图片文件中,通过不同的扩展名区分不同的格式,最常见的图片格式有bmp、jpg和png。bmp是早期的图像存储格式,它直接把图片中每个像素的颜色存储在图片文件中,占空间较大;jpg是最常用的图片存储格式,它用压缩算法将图片内容压缩后存储,占存储空间较小,有时也会损失一些图片的质量,在保存图片时可以设置压缩比例,以便在图片的大小和精度之间达到平衡;png采用无损压缩格式,存储的是带透明通道的图片。

15.1.3 获取图像

图形界面或多或少用到图像,比如:网站的Logo(商标)、软件的欢迎界面、小图标等,游戏为了提升视觉效果会用到更多的图像。

图片可以从网络下载,方法是:打开浏览器,百度图片搜索:images.baidu.com/, 输入想要查找图片的关键字,找到合适的图片后,在图片中点击右键,选择“另存图像为”,即可将网络上的图片下载到自己的电脑上。如图15.2所示:

图15.2 下载网络图片

从网络上下载的图片多数是jpg格式,如果需要透明通道,则要使用绘图软件修改,或者在搜索时指定png格式。

下载网络图片简单快捷,但会涉及图片的版权问题,如果仅用于学习和实验,问题不大。也可以自己用电脑绘制图片,如使用Windows自带的绘图工具:开始->所有程序->附件->画图,绘图后保存成图片文件即可在程序中使用。另外,也可以把手机中的照片文件通过微信传到电脑上使用。常用的绘图工具还有用于修图的PhotoShop,和用于绘图的Illustrator等等。

15.1.4 Python绘图

任何编程语言,操作图片一般都需要三步:读取图片文件、调整图片、显示图片。本例使用游戏开发库pygame操作图片:

第一步,使用pygame.image.load()函数读取图片,它支持主流的图片格式,读取文件后将其转换成pygame的内部图片存储格式。
第二步,使用pygame.transform.scale()函数将图片缩放到指定大小。
第三步,使用画布提供的screen.blit()函数将图片按指定的位置显示在画布(绘图窗口)上。

01 import pygame 
02 
03 WIDTH = 640 
04 HEIGHT = 480 
05 
06 pygame.init() 
07 screen = pygame.display.set_mode((WIDTH, HEIGHT)) 
08 
09 back_img = pygame.image.load('bg.jpg') 
10 background = pygame.transform.scale(back_img, (WIDTH, HEIGHT)) 
11 
12 running = True 
13 while running: 
14 for event in pygame.event.get(): 
15 if event.type == pygame.QUIT: 
16             running = False 
17     screen.blit(background, (0, 0)) 
18     pygame.display.update() 
19 
20 pygame.quit()

第01-07行引入pygame游戏开发模块,初始化,并创建一个宽为640,高为480的窗口。(详见上一讲)
第09行加载当前目录下的图片文件bg.jpg。
第10行将图片缩放成与窗口同样的大小。
第12行设置变量running,用于控制程序主循环。
第13行用while实现程序主循环,当running为True时循环显示,否则退出。
第14-16行接收用户操作,当用户关闭窗口时将running设为False,退出主循环。
第17行用blit方法将背景图片显示在窗口之中(类似于将图像区域复制粘贴到显示区域),显示位置为(0,0)。
第18行更新显示,将内存中的数据显示在屏幕上。
第20行释放pygame资源。

15.2 播放声音

背景音乐和音效也是游戏重要的组成部分,本节介绍播放背景音乐和播放普通音效的方法。

15.2.1 音频格式

与图像一样,声音数据也存储在音频文件中,常见的声音文件有两种格式,常用的扩展名有wav、ogg和mp3。wav也叫波形声音文件,是早期的数字音频格式,占空间较大,不适合较长时间的声音存储,常用于存储长短为几秒钟的音效,例如“叮”的一声响,而mp3是目前比较常用的声音文件存储格式,它使用压缩算法,对音频有一定损失,但相应数据量也较小,便于存储和传输。

15.2.2 获取声音文件

声音文件也可以从网络下载,或者自己录制。Windows系统中也有很多自带的音效文件,在计算机中搜索扩展名为“.wav”的文件即可查找音效文件,使用时可将其复制到程序能访问的位置。搜索方法如图15.3所示:

15.3 查找音效文件

15.2.3 Python播放声音

1. 播放背景音乐

播放声音文件,首先需要初始化声音模块,然后加载要播放的声音文件,最后是播放声音,本例中同样使用pygame游戏开发模块中提供的mixer混音子模块实现播放背景音乐。

使用pygame.mixer.init()初始化声音相关模块。
使用pygame.mixer.music.load()加载常见格式的声音文件。
使用pygame.mixer.music.play()播放声音。
使用pygame.mixer.music.set_volume()调节音量。

程序导入模块和主循环与前一例程相同,此处不再重复。在主循环之前加入以下代码即可循环播放当前目录下的背景音乐back.mp3文件。

01 pygame.mixer.init() 
02 back_music = pygame.mixer.music.load('back.mp3') 
03 pygame.mixer.music.set_volume(0.5) 
04 pygame.mixer.music.play(loops=-1)

第01行初始化声音相关模块。
第02行加载当前目录下的声音文件back.mp3,运行程序前请先将要播放的文件复制到当前目录下。
第03行设置音量为最大音量的50%,以防止背景音乐声音过大。
第04行播放已加载的音乐,并使用loops参数设置播放次数,设置为-1时声音循环播放。

2. 播放其它音效

除了背景音乐之外,有时还需要根据用户的操作或者游戏需要偶尔播放一些音效文件,方法如下:

01 dound = pygame.mixer.Sound('warning.wav') 
02 dound.play()

第01行用于加载音效文件。
第02行用于播放音效,默认为播放一次。

需要注意的是:以Sound方式加载的音效文件有一定的格式要求,只能播放简单格式的wav和ogg文件,当格式不符合要求时,程序将报错“Unable to open file”。另外需要注意的是在播放完音效后不能马上结束程序,否则将听不到声音的播放效果。

15.3 综合实例

本节将通过游戏“愤怒的小鸟”,学习游戏常用的程序技术,首先使用git下载源码(git使用方法详见前一讲)。

在git bash中输入以下命令下载“愤怒的小鸟”项目:

$ git clone http://www.github.com/estevaofon/angry-birds-python angry-birds-python

该程序还依赖三方模块pymunk,在Anaconda Prompt中,用以下命令安装:

$ pip3 install pymunk

进入下载后的angry-birds-python目录,可以看到程序包的具体内容,如图15.4所示:

图15.4 愤怒的小鸟项目

其中src为source code的缩写,意思是源代码;resources译为资源,其中包括游戏用到的图片和音效文件,有时也简写为res;README.md是说明文件,用Windows记事本打开该文件,可以看到其中介绍了该软件依赖的三方模块,以及运行该程序的方法;LICENSE是软件的版本信息。请读者自行进入每个目录,通过文件名和文件扩展名了解它们的用途。

之前讲解的例程中,为了方便调用,资源文件、代码文件以及说明文件常存储在同一个目录下面,而当程序中有多个代码文件和资源文件时,目录内容将变得非常混乱,建议读者在之后的项目中利用目录更好地分类和管理文件。

从Readme.md文件中可以看到,程序的入口(主要程序)是main.py,绝大多数项目的主程序名都为main.py,这也是约定俗成的命名习惯。请读者在Spyder或者Jupyter中打开main.py,并运行该游戏,了解“愤怒的小鸟”的游戏规则。

请读者在main.py中找到主循环、用户事件处理、以及绘图的相应代码,上一讲学习了对键盘事件的处理,本讲请读者自学对鼠标事件的处理(提示:鼠标关键字“MOUSE”)。

通过玩游戏可以了解:本游戏除了包含图片和声音之外,主要的难点在于物体的碰撞效果,碰撞效果使用pymunk三方库实现。它是一个物理计算引擎,很多游戏的运动效果都借助该库实现。

课后练习:(练习答案见本讲最后的小结部分)

练习一:实现简单版愤怒的小鸟,具体要求如下:

  1. 游戏目标:接收用户鼠标事件,根据鼠标按下时长决定投掷小鸟的远近。当小鸟打中猪时,游戏结束。
  2. 前景和背景用图片显示,至少两个前景物体:小鸟和猪。
  3. 带背景音乐和用户操作音效,用户点击鼠标时播放音效。
  4. 提示:参考以下代码06-09行计算抛物线的轨迹:
01 import math as m # 引入数学函数库 
02 import matplotlib.pyplot as plt 
03 %matplotlib inline 
04 
05 # v是力度取值(100-1000), a是角度取值(0.1-2), width为窗口宽度 
06 def calc(a,v,width): 
07     arr = [m.floor(0.5+x*m.tan(a)-x*x/(v*m.cos(a))) for x in range(width)] 
08     arr = [i for i in arr if i >= 0] 
09 return arr 
10 
11 arr = calc(1.3,800,640) 
12 plt.plot(arr) 
13 arr = calc(0.5,800,640) 
14 plt.plot(arr)

程序运行结果如图15.5所示:

图15.5 抛物线图

本讲内容不多,但是练习的难度较大,对于完全没有编程经验的读者,是一个巨大的考验。编写程序的最终目标是实现完整功能,而不是照猫画虎地做秀,增加难度也是必经的过程。

15.4 思维训练

15.4.1 解决复杂问题

本讲中的习题,不像之前的练习,照猫画虎就能完成,需要把学到的知识打散,再组合。小李同学在放假时做了四遍:第一天两遍、第二天一遍、第三天一遍,每做一遍之后,把源码删掉,再重新写。

一开始做的时候问题不断,以她三年级的英语水平,报错基本都看不懂。在常量、变量、坐标系、列表、表达式,判断和循环的缩进中,暴露出了很多前期学得不扎实的知识点。但随着不断地重复,提出的问题也越来越少。

最后她说她都把这五十多行代码背下来了,让她背了一遍,流程基本都对。有点像多年前流行背《新概念》英语中的例文。

下面分享一下解题思路:

第一步:拆分问题——把一个大问题拆分成几个小问题。

小李把问题分解为:1接收鼠标事件、2打到猪退出程序、3显示图像、4点鼠标播放音效、5根据鼠标时长确定小鸟的飞行距离。在这一步,小朋友切分的粒度不够完美,比如应该把小鸟按抛物线运动单列出来。但框架基本正确。

第二步:确定依赖关系,排列解决“小问题”的顺序。

由于问题之间存在前后的依赖关系,同时还需要考虑难易程度,顺序排列为:3->4->1->5->2。

第三步:按步骤解决“小问题”。

新手程序员常犯的错误是:把所有想到的功能都加上,然后再开始调试。可一旦遇到问题,就很难定位问题出在哪儿。建议每做完一步,调试通过后再做下一步。

对小朋友来说,每解决一个小问题,都是一次小小的成功,这个过程也是不断地肯定自己的过程。在最后一遍练习中,她开始大量使用print语句打印状态信息。基本跳出了瞎蒙的状态。

15.4.2 统筹规划

统筹规划是运用统筹兼顾的基本思想,对错综复杂、种类繁多的工作进行统一筹划,合理安排的方法。对于解决复杂的问题尤为重要。

1.层进式优化

在刚开始学习画画时,老师要求,先确定构图,然后画线稿;铺调子;再一遍一遍逐渐深入印画。

图15.6 层进优化

这种方法在软件工程中叫作螺旋模型,它不追求一次到位,而是把整个过程从时间分为多个阶段,每个阶段都包含:计划、执行、检查。 它有以下优点:

  • 如果工程中断,也保留了阶段性的成果,基本可用。
  • 当遇到一些关键错误,能及时发现和调整。
  • 时间规划合理,不会为一些细节的不完美影响大局。
  • 以整体为出发点,不会出太大问题,能更好把握时间和进度。
  • 虽然不要求一次做到最好,但随着工作的深入和进一步的理解,也能把握细节。

一位娴熟的画师从任何一点起笔都能完成一幅作品,因为整个过程都在他的脑中;但是对于摸着石头过河的初学者,仍需要一些步骤和方法。

小朋友常见的问题是:做作业时很可能因为对其中一项内容的精益求精,花掉了大多数时间,发现时间不够之后,其它作业就只能草草了事。导致整体水平偏低。自己也很委屈:“我认真难道还错了吗?”。这种问题只需要在安排上做一些微调就能解决。

2.计划

首先是切分问题,不只是切分工作量,切分步骤,还有切分时间。根据不同情况有不同的选择,需要兼顾各种条件。

切分之后,需要排列优先级,有人选择先做简单的,有的先做难的。更细化地可以分成:难度优先级,步骤依赖关系的优先级,重要性优先级,时间优先级……有时候把问题列出来之后,结果就显而易见了。

当事情太多,可能做不完时,“重要性”是判断标准,需要把不重要的往后排,或者去掉一些不重要的安排。也可以从另一个角度考虑,是一个做完再做一个,还是先把每件事做成60分水平,有时间再进一步优化。

当问题足够复杂,步骤很多时,还需要列出步骤清单。

3.实施

实施就是照着计划做,也叫做执行力,在几个步骤之中好像最为简单,实际对于一个长期或者有难度的计划,成年人也很难做到,比如能减肥成功又保持十年内不反弹的人少之又少。计划是否能正常实施很大程度上取决于计划的难度和合理性。

当然,也与人的意志力自控力强弱有关。

4.设置检查点

想都不想就去做的反面是想得多做得少:我是否找到了最佳方向?坚持努力有没有意义?这个问题在成年人身上更加明显,往往在纠结中浪费了大量的时间和精力。很多时候,如果不深入到一定程度,就无法判断最终结果。

层进式工作,并且在过程中设置检查点,可以有效地解决这一问题,即使出现方向性问题也能及时止损。

有时候我们已经习惯听话,只要是老师说的,领导说的,都必须照做,而缺乏对整体的规划和对解决方案思考。在时间和能力条件都有限的情况下,有时候即使做了,效果也不好。如果总是指哪儿打哪儿,判断力从何而来?任何行业,最重要的都是提出问题和提出方案的人,而最没技术含量的是那些不用思考和判断的简单工作。

规划力是一种基础能力:规划、评价、按计划实现的能力。训练得越早,越能应用到其它领域,变成习惯的思维方式。画画、书法、弹琴、运动、学习都能用到,为什么一个小朋友钢琴五级需要学习三五年时间,而有些成年人花一年就可以练到同样程度?这些能力都是在成长过程中慢慢累计而成的。

规划力可以通过编程训练,通过其它日常活动也能锻炼,比如做一顿饭,设计搭配,规划时间,其中的顺序。采买各种食材,找菜谱,在做的过程中发现和补救……

需要注意的是:整件事需要足够复杂,过程中也需要不断思考和判断,此过程也需要根据年龄由浅入深,给孩子足够的空间,也允许他们在过程中犯错。

15.5 小结

15.5.1 单词

本讲需要掌握的英文单词如表15.1所示。

表15.1本讲需要掌握的英文单词

15.5.2 习题答案

  1. 练习一:实现简单版愤怒的小鸟。
01 import pygame 
02 import time 
03 import math as m
04 
05 def calc(a,v,width): 
06     arr=[m.floor(0.5+x*m.tan(a)-x*x/(v*m.cos(a)))for x in range(width)] 
07     arr=[i for i in arr if i >= 0] 
08 return arr 
09 
10 arr=calc(1,800,640) 
11 
12 x=0 
13 y=0 
14 
15 WIDTH=649 
16 HEIGHT=480 
17 s=50 
18 pygame.init() 
19 screen=pygame.display.set_mode((WIDTH,HEIGHT)) 
20 
21 bg_img=pygame.image.load('bg.jpg') 
22 bg=pygame.transform.scale(bg_img,(WIDTH,HEIGHT)) 
23 zhu_img=pygame.image.load('pig.png') 
24 zhu=pygame.transform.scale(zhu_img,(s,s)) 
25 niao_img=pygame.image.load('bird.png') 
26 niao=pygame.transform.scale(niao_img,(s,s)) 
27 
28 pygame.mixer.init() 
29 back_music=pygame.mixer.music.load('bg.ogg') 
30 pygame.mixer.music.set_volume(0.6) 
31 pygame.mixer.music.play(loops=-1) 
32 
33 running=True 
34 while running: 
35     for event in pygame.event.get(): 
36         if event.type==pygame.QUIT: 
37             running=False 
38         if event.type == pygame.MOUSEBUTTONDOWN: 
39             b=time.time() 
40         if event.type == pygame.MOUSEBUTTONUP: 
41             a=time.time() 
42             i=a-b 
43             dound=pygame.mixer.Sound('warning.wav') 
44             dound.play() 
45             arr=calc(1,i*500,640) 
46             x=0 
47     if x>580 and x<640 and y>400 and y<470: 
48         running=False 
49
50     if x<len(arr)-1: 
51         x=x+1 
52         y=arr[x] 
53         y=HEIGHT-y 
54     screen.blit(bg,(0,0)) 
55     screen.blit(zhu,(580,400)) 
56     screen.blit(niao,(x,y)) 
57     pygame.display.update() 
58 
59 pygame.quit()

少儿Python编程_第十四讲:开发游戏

无论哪一种编程语言,实现图形界面程序的方法都大同小异。本讲介绍用Python开发小游戏的方法,从中学习使用Python编写图形界面的程序,图形图像的基础知识,以及在图形界面程序中与用户交互。最后部分还将学习使用版本管理工具下载他人的代码。

14.1 图形化应用程序

之前学习过的程序都相对简单:程序顺序执行,如图14.1左侧流程图所示,程序用字符显示输出信息。而带窗口界面的程序,无论是工具界面(如记事本),还是图像界面(如游戏),程序都包括三部分:

  • 初始化 初始化界面绘制模块,设置窗口属性(如:长、宽)、做装载图片和声音文件等准备工作。
  • 主循环 主循环等待接收用户输入的信息(鼠标或键盘输入),并对用户输入做出反馈(在界面上显示)。同时不断执行程序(如推进游戏过程)。
  • 退出 退出程序关闭已打开的窗口、释放申请的资源等等。

带界面的程序启动后一直运行,直到用户关闭窗口或者在界面上选择退出时程序结束,如图14.1右侧流程图所示。

图14.1 程序流程图

14.2 绘图区域

在电脑或者手机设备上显示的图片是由MxN个点组成的,其中的每一个点也叫做像素。每个像素大小一致,颜色不同。描述颜色的方法也有很多,在计算机中最常用红(RED)、绿(GREEN)、蓝(BLUE)描述一个像素点的颜色,它们分别代表每种颜色的亮度,也称为RGB。

Python编程时,颜色常写成含有三个元素的元组,如(0,0,0)的RGB三个值都为0不发光,即黑色,而(255,255,255)三个值都为其最大值255最强光,即白色。255是用8位二进制数所能描述的最大值,也就是说每一位颜色用一个字节(8位)表示,一般3个字节描述一个像素点,有时也用四个值描述,如(255,255,255,255),前三位是颜色,最后一位是透明度,透明度的范围也是0-255,255为不透明,0为完全透明。

Python编程时,一般将窗口作为画布绘图,窗口左上角位置为 (0,0),横坐标在前,纵坐标在后,越向右侧横坐标值越大,越向下纵坐标值越大。横向常用x表示,纵向常用y表示,即(x,y),如图14.2所示。

注意:起始坐标从0开始,而不是1。

图14.2 绘图区域图示

图中的颜色区域被描述为 (4,2,3,2),依次是起始横坐标4,起始纵坐标2,宽度3,高度2。

14.3 Pygame

在Python环境下编写游戏比较简单,三方库pygame是常用的Python游戏编程工具,提供了图像、声音的支持。

使用前需要先安装pygame模块,在Windows下打开:开始->所有程序->Anaconda3的Anaconda Prompt命令行,使用以下命令安装模块:

01 $ pip install pygame

本讲也通过编写pygame游戏了解图形图像程序的编写过程。下例将在窗口中绘制矩形,并根据用户输入的上下左右按键移动矩形的位置。

01 import pygame 
02 import sys 
03 
04 pygame.init() 
05 screen = pygame.display.set_mode((640, 480))  # 设置窗口宽640高480 
06 
07 x = 0 # 横坐标 
08 y = 0 # 纵坐标 
09 while True: 
10 for event in pygame.event.get(): # 遍历所有事件 
11 if event.type == pygame.QUIT: # 如果单击关闭窗口,则退出 
12             pygame.quit() 
13             sys.exit(0) 
14 if event.type == pygame.KEYDOWN:  
15 if event.key == pygame.K_UP: 
16                 y-=1 
17 if event.key == pygame.K_DOWN: 
18                 y+=1 
19 if event.key == pygame.K_LEFT: 
20                 x-=1 
21 if event.key == pygame.K_RIGHT: 
22                 x+=1 
23     screen.fill((0, 0, 0)) # 填充背景颜色为黑色 
24     rect = pygame.Rect(x,y,100,100) # 设置绘图区域 
25     pygame.draw.rect(screen, (255,0,0), rect, 0) 
26     pygame.display.flip()  
27     y+=0.005

第01-02行引入模块。
第04行初始化pygame模块。
第05行设置窗口大小。
第07-08行创建变量用于设置和存储矩形位置。
第09行为主循环,确保窗口一直显示,直到程序退出。
第10-22行响应用户操作。
第11行响应退出事件,当用户关闭游戏窗口时,此事件被触发。
第12行释放游戏资源。
第13行退出程序。
第14行响应键盘按下事件。
第15-22行对键盘的上下右左右四个按钮分别处理,改变x,y值。
第23行将窗口背景绘制为黑色。
第24行设置一个矩形区域,四个参数分别指定矩形起点的x坐标、y坐标、宽度和高度分别为100。
第25行在窗口上绘制该矩形,函数的第一个参数指向绘制窗口,第二个参数指定颜色为红色,第三个参数指定绘制位置,第四个参数指定区域内部填充颜色。
第26行用flip方法更新显示区域,此时绘制出来的图像被显示在窗口之中。
第27行y值增加,使得在用户不按键的情况下,红色矩形也向下移动。

本例中的程序类似于游戏“俄罗斯方块”,下一讲将从网络下载真正的“俄罗斯方块”游戏代码,进一步学习编写此类小游戏的技能。

课后练习:(练习答案见本讲最后的小结部分)

练习一:请在窗口中绘制背景为白色,前景为绿色的米老鼠头像,如图14.3所示,按任意键退出程序。
提示:画圆的方法是:
pygame.draw.circle(画布, 颜色, 圆心点, 半径, 填充方式)
例如: pygame.draw.circle(screen, (0,255,0), (100,100), 50, 0)。
与绘制矩形不同,绘制矩形需要指定矩形左上角坐标(横坐标、纵坐标)、宽和高,绘制圆形指定的是圆心点坐标(横坐标100、纵坐标100),圆的半径50。

图14.3 绘制米老鼠效果图

14.4 Git软件管理

Git是分布式版本控制系统。当编写软件时,在不同的开发阶段可能需要保存多个版本的代码和数据。使用Git可以管理数据和代码的不同版本。

GitHub是一个面向开源及私有软件项目的托管平台,它是远程的服务器,开发者可以将自己的代码上传到GitHub服务器,供他人下载,或者仅供自己和有限的几个人可见。可供所有人下载的软件和数据叫做“开源软件”;仅自己可见的叫作“私有软件”。目前Github拥有超过900万开发者用户,大量可以下载的高质量代码。

本讲将介绍从GitHub下载他人公开的游戏代码,从中学习游戏的编写方法。

14.4.1 安装Git软件

Git早期只支持Linux和Unix,现在也可以在Windows上运行,但需要安装软件。先下载软件,打开git-scm.com/downloads,选择Windows版本,稍等片刻之后自动开始下载;下载后按提示选择Next和Install默认选项安装软件即可。

软件安装成功之后可从Windows开始菜单中打开,开始->所有程序->Git->Git Bash,此时Git命令行被打开。

14.4.2 下载游戏代码

使用以下命令下载程序源代码,如图14.1所示:

01 $ git clone https://github.com/lovetianya/pygame-development.git
图14.4 下载项目的代码

pygame-development是GitHub上的开源游戏代码,其中实现了俄罗斯方块、贪吃蛇等小游戏。

用pwd命令可以看到当前目录,程序代码下载到了当前目录之中,其中的els目录中是实现俄罗斯方块的代码和相关的资源,如图14.5所示。font目录下是游戏中用到的字体,pictures目录下存储的是图片,run-this.py是用Python编写的程序源码,用Spyder打开它,或者复制到Jupyter Notebook中即可运行。此处建议用Spyder打开程序并运行(开始->所有程序->Anaconda3->Spyder)。

图14.5 俄罗斯方块相关资源

课后练习:

练习二:运行游戏“俄罗斯方块”、“贪吃蛇”、“五子棋”,并阅读其源代码,找到其中的主循环、按键响应、以及绘图的相关代码。

14.5 思维训练

14.5.1 举一返三

上一讲提到了通用人工智能AGI,即建立拥有广泛且适应性强的智能,其中包括将学习到的有限知识应用到更多的领域之中。本部分来探讨人类如何实现了举一返三。

1.常识系统

机器不能像人一样思考或者我们认为机器缺乏创造力,很大程度上是因为没有常识系统,目前的机器学习模型,一般都针对具体单一的功能,写文章的只懂写文章,识别图像也只关注图像本身,比如GPT-2模型通过学习所有金庸先生的小说,撰写了如下的文字。

图14.6 模型生成文本

如果读过《天龙八部》这部小说就不难发现,虽然在语言风格上问题不大,但人物关系不太正常。这是因为模型只模仿了文章的语言风格,模型通过学习阅读大量文字,根据前文计算下一个字最可能是什么,但它不知道“段誉”究竟是什么意思;以及段誉和王语嫣之间是什么关系。

写作的人将脑中的思维框架转换成文字,并试图在读者脑中构建起类似的结构,其中包含大量的常识和背景知识,比如通过故事发生的时间、地点、氛围、故事风格,激活读者脑中的某种场景,这些都是文字之外的信息。思维中故事的框架是多层次的网络,而机器所识别的文字只是相对扁平的结构。

人在成长中构建起丰富的常识系统。知识面越宽广,经验越丰富,就越具有优势。

2.生成框架

解决问题的框架,或者叫作流程、套路,就像是程序中的函数。把某种功能封装在函数之中,在之后遇到同样问题时,就可以直接使用。

写程序处理问题的过程可细分成:获取、整理、使用。如果要实现某一功能,首先,要找到需要的数据比如Excel表;以及处理数据用到的方法如安装第三方库;有了这些基本元素之后,开始编写成程序,然后运行程序实现功能。

除了这些基本步骤以外,有经验的程序员在程序正常运行之后,还会对程序做进一步优化:

  • 让程序变得可重用:比如把其中的各部分功能拆分成函数,以便之后在其它场合继续使用。函数除了能满足当前需要的功能,还要考虑满足未来的扩展功能。
  • 优化程序运行速度和程序结构:比如功能类似的函数是否可以合二为一。
  • 加强程序的健壮性,在遇到小问题时也能正常使用。
  • 规范化格式以及命名,加入注释,使程序更加清晰易懂。

同样道理,在学习和实践之后,我们也需要反思:是不是可以做得更好?还需要做出哪些调整,或者加强训练;能否从复杂的过程中提取出几个重要经验模块?这些经验还可以用到什么场合?

在编写函数、整理代码的过程中,就可以很好地训练这方面的能力。

3.拆分

处理复杂问题时,几乎不会遇到两次完全相同的情况,但可能遇到过程中的某一部分与之前的经验重合。就像本讲的练习中画出米老鼠头像可能让人觉得毫无头绪,但是拆开看,米老鼠头由三个相互重叠的圆形组成。

解决复杂问题通常需要:拆分成单个问题、解决单个问题、处理各个问题之间的关系。调试程序也是同样道理,如果不能确定整体程序在什么位置出错,分块调试也是有效的方法。

4. 相似性

对比和类比也曾被认为是人类特有的灵性。二者有一个共同的特点,就是被比较的两者之间一定存在共性。类比很容易理解,比如把一片落叶比做蝴蝶,因为它们在风中具有相似的姿态。而对比也需要共性,虽然高和矮完全不同,但它们描述的都是长度。

从总结规律的角度看,只要一种规则反复出现,就可以被提取;从使用的角度看,由于具有相似性,可以使用已有的经验处理未知的情况。

5.代入框架和迁移学习

很多人死读书,虽然记住了,但是场景稍有变化就不会使用。下面来看看机器是如何实现迁移学习,在不同的场景之中使用旧有的技能。

迁移学习是人工智能领域近几年的热门方法,比如它先使用大量图片训练模型,训练出了模型对于图片的常识,包括对明暗、边角、形状等等,如果最终需要识别图中的水果,在使用之前,再用少量的水果图片进一步训练模型即可使用。

可以说迁移学习的本质是使用大量数据训练常识,再加入微调。将已有的常识和当前的场景结合起来,解决当下的问题。通过对比相似性,使用旧框架,如果无效,也可以使用少量新数据训练调整旧有框架。

当头脑中存储了大量框架,并且整理成清晰的结构,就更容易和当前场景结合。

好方法事半功倍,但再好的方法也需要练习。

14.5.2 创新

人们常常认为机器在创新和想象方面无法超越人类?是否真是这样?让我们先来看看机器在棋类比赛中的表现。早在20年前,IBM的深蓝就打败了国际象棋大师,这已不再是什么新闻。在2017年10月在《科学》杂志上发表了一遍关于AlphaZero的论文,它的惊人之处在于,AlphaZero无需人类指导,仅仅通过自己与自己对弈,就快速地理解了国际象棋的规则,成为了目前为止最好的棋手。

比胜利更重要的是,AlphaZero是自学成材,它具有自己的洞察力,而非被人教会,而且它还自创了一些出乎人们意料的策略,以致于,在后来的人类比赛中,如果有人出现非常精妙的走法,都可能被怀疑是使用计算机作弊。

再来看看什么是创新,申请专利时把创新分为三种:

第一种是发明专利,它是针对产品和方法产生新技术方案。就像爱迪生发明电灯,他通过1000多次不同材料的实验;而现今,科学家利用虚拟现实和分子技术,极大地优化了实验过程。比如在荷兰代尔夫特理工大学,正尝试使用贝叶斯模型寻找一种聚合物排列方法,使材料变得坚固、轻量和可折叠。

第二种是实用新型专利,它是对产品的构造、结构、形状提出更加实用的新方案。就像瓦特发明蒸汽机的故事,实际上瓦特并非蒸汽机的发明者,而是蒸汽机的改造者,应该说他发明了第一台有实用价值的蒸汽机。这种创新以优化和改造为主。

第三种是外观设计专利,这种专业偏重设计,与艺术相关,目前人工智能已经可以画慢画、谱曲、写作、创造各种艺术作品,也有人说,机器主要偏重模仿,没有艺术家的灵魂。而从上面武侠小说的例子可以看到,目前机器学习的模仿效果已经非常强大。BERT模型也可被用于生成故事的简介。如果模型学到了人物的关系,以及创建故事的规则,理论上也能编写故事。

无论是修改旧方法还是创造新方法,都用到猜谜原则(试错),不断试错,其具体方法是随机修改重要特征,看是否解决了问题,或者效果是否变得更好。进而拆成小块不断式错,向目标靠近。在穷举方面,机器胜过人类。而相比之下,人类在常识和解决复杂问题方面更占优势。

这些方法能让机器学会,不论天赋,更何况是正常人类。真实世界比棋盘上的可能性多得多,无法通过单纯的试错学习。在当前阶段,人机结合往往能达到最好的效果。人负责定义问题,构建和管理整体结构,而机器负责具体的工作。比如:某人想到了一个很好的故事,但文笔不够好,通过与机器结合,就能达到更加完美的写作效果。

14.6 小结

14.6.1 单词

本讲需要掌握的英文单词如表14.1所示。

表14.1本讲需要掌握的英文单词

14.6.2 习题答案

1.练习一:请在窗口中绘制背景为白色,前景为绿色的米老鼠头像,如图14.3所示,按任意键退出程序。

01 import pygame 
02 import sys 
03 
04 pygame.init() 
05 screen=pygame.display.set_mode((1000,1000)) 
06 
07 while True: 
08 for event in pygame.event.get(): 
09 if event == pygame.QUIT: 
10             pygame.quit() 
11             sys.exit(0) 
12 if event.type==pygame.KEYDOWN: 
13 if event.key==pygame.K_UP: # 按上键退出 
14                 pygame.quit() 
15                 sys.exit(0) 
16     screen.fill((255,255,255)) 
17     pygame.draw.circle(screen,(0,255,0),(100,100),50,0) 
18     pygame.draw.circle(screen,(0,255,0),(175,225),100,0) 
19     pygame.draw.circle(screen,(0,255,0),(250,100),50,0) 
20     pygame.display.flip()

2.练习二:运行游戏“俄罗斯方块”、“贪吃蛇”、“五子棋”,并阅读其源代码,找到其中的主循环、按键响应、以及绘图的相关代码。

以贪吃蛇为例,“while running”中的是主循环,“event.key”相关的是按键处理,“draw_”相关的是绘图。

少儿Python编程_第十三讲:舵机和机械臂

机器人和机械臂是青少年最感兴趣的领域。本讲来看看制作机器人都需要哪些技术,实验部分在单片机上写Python程序实现用游戏摇杆控制舵机,再用舵机连接机械爪抓取物体,效果类似抓娃娃机。

13.1 机器人技术

机器人的英文是Robot,Robot最早出现在科幻剧《罗素姆万能机器人》中,意思是“人造工人”。 机器人正逐步进入人类的生活:玩具机器人、扫地机器人、无人机、巡逻机器人、野外作业机器人……它们形态各异,比如扫地机器人看起来完全不像人类;也有一些看起来有头和四肢能听会说的人形机器人。

最近几年机器人技术发展很快,其中的机械臂技术已经比较成熟,在工业领域广泛使用,甚至在某些领域已经替代了工人;在特殊领域专业机器人也开始发挥作用,比如无人机拍摄,手术机器人,搬运机器人等等;而在人形机器人、自动驾驶等相对复杂的领域,当前还处于研发和演示阶段,开发者也在进一步的探索:如何改进技术,以及当前的技术在哪些领域可以发挥作用。

下面将分别介绍机器人技术的两个组成部分:思考和运动。

13.1.1 机器人运动

机器人由硬件和软件两部分组成,日常看到的主要是硬件部分,设计师需要同时考虑功能、生产水平、美观、造价等因素设计硬件。

研究发明和生产产品不同,研究和发明需要大开脑洞,尽量多做实验,掌握和发明最高级的技术;而生产产品,则需要注重功能,在成本最低的情况下,安全稳定地实现核心功能,去掉华而不实的部分。

比如机器人大会上展示较为高级的机器人或者机器动物,用腿行进,需要控制每一个关节的角度,各个关节协同工作,非常复杂,技术领先。而大多数情况下,机器人只需要在平地行进,而类似车的行进方式就可以实现该功能,方法简单,而且成本低。在野外环境,也可以使用类似坦克行进方式的履带机器人。

1.电机

智能小车、传送带,机器手机械臂的关节,机器人眼睛的转动,都是由电机驱动的。电机按功能分为以下几种:

  • 直流电机 直流电机是最为简单的电机,通电就向一个方向旋转,不通电就停止,通过电流大小控制旋转速度,比如控制小车、风扇等。
  • 步进电机 步进电机可以控制旋转的角度,以角度为单位转动,相对转动更精确,常用于打印机、磁盘驱动器等设备。
  • 伺服电机 伺服电机则更加高级,它可以控制转动的速度和精确角度,其内部包含电机、控制器和传感器,传感器可以检测当前的角度。可将它看成一套电机系统。 舵机是低端的伺服电机系统,也是最常见的伺服电机系统,它常用于实验,便宜的舵机只有几块钱。

2.自由度

自由度是运动时所必须给定参数的数目,一个机械臂通常需要多个电机配合协作,一般6-7个自由度,如图13.1所示。在设计机械臂时,不仅需要考虑最终的位置,还需要考虑到达位置所需的过程,以及从一个位置切换到另一位置所经过的路径是否可到达,是否合理。

图13.1 机械臂

自由度是评价机器人的重要指标,一般可以在运动机器人的说明书中看到自由度相关的说明。在2019年机器人大会上还展示了三十多个自由度的人形机器人,由此也可以想到控制该机器人的复杂程度。

3.运动相关技术

机器人运动的过程中,需要能够识别周围的场景,躲避障碍,在保证自身安全的同时,不对周围的人或者物造成伤害。可能用到距离探测、寻找到达指定位置的路径、摄像机和机器视觉中的物体识别(识别是什么物体)、以及轮廓识别等等技术。

13.1.2 机器人对话

除了运动以外,与其它设备交互、用语音与使用者互动也是机器人的重要用途。很多功能用户通过计算机和手机也能实现,但需要通过鼠标、键盘、触摸屏输入,设备以图片或者文字的形式将结果展示给用户,与机器人对话可以使这些工作变得更加简单和顺畅,简化人的操作。

其背后的技术除了网络支持,最重要的是图像技术、语音技术、以及知识系统。以语音问答为例,首先,机器人需要将用户的语音数据转换成文字,识别其中的关键语义,然后调用问答系统,找到答案,最终再使用语音合成技术把文字答案转成语音,播放给用户,其中任何一个环节出错都可能导致错误的结果。

目前语音识别、合成、语义、问答系统都可以使用现成的服务实现基本功能,例如讯飞人机对话、百度大脑开放平台等等。也就是说读者无需学习复杂的原理和算法,只要掌握简单的接口调用也可以构造自己的机器人对话系统。但它们提供的功能比较简单,如果想使用订酒店、买车票、找攻略,这种步骤复杂的功能目前还是使用手机或电脑软件效果更好。

课后练习:(练习答案见本讲最后的小结部分)

练习一:寻找生活中的机器人,比如:玩具机器人,商场医院银行的服务机器人,扫地机器人,或者网络上的图片。分析:它的软件和硬件方面使用了哪些技术,有几个自由度。

13.2 游戏摇杆

游戏双轴摇杆传感器模块采用金属摇杆电位器制作,常用于制作遥控器等互动项目使用。它具有VRx(X轴)Vry(Y轴)2个模拟输出,SW(Z轴)1个按钮数字输出。数字信号是一些离散的信号,通常使用1和0表示,模拟信号是连续的信号,一般用数值表达。

当向前后左右转动摇杆时,VRx(X轴)和Vry(Y轴)根据转动的角度大小获取数值。当用户向下按时,SW(Z轴)输出高电平1,否则输出低电平0。

本例使用单片机读出摇杆当前的状态,并根据不同状态点亮单片机上的LED灯,在摇杆按下时点亮第2盏灯,在摇杆延X轴不同方向变化时分别点亮第三和第四盏灯。

接线方法如图13.2所示:

图13.2游戏摇杆连接示意图
01 import pyb 
02 
03 pin_z = pyb.Pin('X3', pyb.Pin.IN) 
04 pin_y = pyb.ADC(pyb.Pin('X4')) 
05 pin_x = pyb.ADC(pyb.Pin('X5')) 
06 
07 led_2 = pyb.LED(2) 
08 led_3 = pyb.LED(3) 
09 led_4 = pyb.LED(4) 
10 
11 while True: 
12 if pin_x.read() > 3000: 
13         led_3.on() 
14         led_4.off() 
15 elif pin_x.read() < 2000: 
16         led_3.off() 
17         led_4.on() 
18 else: 
19         led_3.off() 
20         led_4.off() 
21 if pin_z.value() == 1: 
22         led_2.on() 
23 else: 
24         led_2.off()

第01行引入pyb三方库用于操作单片机。
第03行以数字方式(非模拟方式)打开X3针对应的接口,用于读取“按下”操作。
第04行以模拟方式打开X4对应的接口,用于读取y方向角度。
第05行以模拟方式打开X5对应的接口,用于读取y方向角度。
第07-09行建立变量用于控制三个LED灯。
第11行开启主循环。
第12-14行判断x坐标大于3000时(向右转动),开第三盏灯关第四盏灯。
第15-17行判断x坐标小于2000时(向在转动),开第四盏灯关第三盏灯。
第18-20行处理在2000-3000范围内的数值(X轴上无操作),关闭三四盏灯。
第21-22行判断摇杆是否按下,如果按下,则点亮第二盏灯,否则关闭第二盏灯。

运行此程序后,转动摇杆,或者按下摇杆,不同的灯亮起。

13.3 控制舵机

舵机,又称伺服马达。主要用于角度控制,用它连接不同扩展硬件可以实现不同功能。比如用它连接机械爪,可以控制机械爪打开或关闭,以抓取物体;用舵机前后两端各连接机械臂的一部分,通过转动控制机械臂的曲伸,连接智能小车上的距离传感器,可以在小车不转向的情况下,测试各个方向的距离,转动电子眼也使用相同方法。

它的工作原理是由控制器发送PWM(脉冲宽度调制)信号给舵机,驱动马达转动,同时由位置检测器(电位器)返回位置信号,判断是否已经到达设定位置,一般舵机可向左旋转90度,向右旋转90度,整体旋转范围180度。因此如果想在上下左右四个方向转动需要两个舵机配合。

1.接线

舵机一般有3根线,棕色为地线与GND连接,红色为电源与VIN连接,橙色为信号线,本例中与X1针连接(不同品牌的舵机,线的颜色可能不同)。如果连线接反,可能烧坏舵机,如果发现连线或者舵机发热,请尽快断电,并检查插线情况。

图13.3 舵机连接示意图

2.控制原理

舵机转动的角度是通过调节PWM信号的占空比来实现的。占空比指高电平在一个周期之内所占的时间比率,如图13.4所示。比如:标准PWM信号的周期固定为20ms(50Hz),理论上脉宽范围在1ms到2ms之间,但是,事实上脉宽在0.5ms到2.5ms之间,脉宽和舵机的转角0°~180°相对应。

图13.4脉冲信号示意图

舵机基于通过控制线发送的脉冲的持续时间转动,脉冲长度将决定电机转动的距离。例如:1.5ms脉冲将使电机转到90度位置。短于1.5ms将其沿逆时针方向移向0度位置,任何长于1.5ms的信号都会使舵机构顺时针方向朝180度位置转动。

13.3.1 操作舵机方法一

TPYBoard控制舵机有两种方法,第一种方法是向舵机发送脉冲信号,控制舵机旋转,是对上一小节原理的实现。第二种是使用封装好的控制函数控制舵机。

本例介绍第一种方法的代码实现,其功能是根据单片机的倾斜角度控制舵机转向。单片机的角度通过TPYBoard上的加速度传感器获取,具体原理已在第11讲详细介绍。

01 import pyb 
02 import time 
03 
04 servo = pyb.Pin('X1', pyb.Pin.OUT_PP) 
05 accel = pyb.Accel() 
06 
07 while True: 
08     x = accel.x() 
09     servo.high() 
10     l = 0.0001*x + 0.0015 
11     time.sleep(l) 
12     servo.low() 
13     w = 0.02 - l 
14      time.sleep(w)

第02行引入time库,用于更精确地控制等待时间。
第04行以输出方式打开X1针指向的接口。
第05行获取加速度传感器对象,用于后面读取单片机角度数据。
第07行开启程序主循环,程序将一直循环运行。
第08行读取加速度传感器x方向上的值,x取值范围在-50~50之间。
第09行向舵机输入高电平。
第10行计算高电平持续时间,以1.5ms为基数,根据x的值进行微调。如果x为-20,则l为0.0001(-20)+0.0015=0.0013,如果x为30,则l为0.000130+0.0015=0.0018。
第11行设置等待时间为l,即高电平持续时间。
第12行向舵机输出低电平。
第13行用完整周期20ms减去高电平持续时间,得到剩余时间w。
第14行设置等待时间为w,即低电平持续时间,以等待脉冲周期结束。

13.3.2 操作舵机方法二

本例介绍使用包装好的舵机控制函数操作舵机,该方法更加简单直观。

01 import pyb 
02 
03 accel = pyb.Accel() 
04 servo = pyb.Servo(1) 
05 
06 while True: 
07     x = accel.x() 
08     servo.angle(-x*2,300) 
09 pyb.delay(200)

第04行获取封装好的舵机对象。
第08行直接设置角度为-x*2,如果x为20,则角度为-40度。
第09行等待200毫秒,以免读取数据过于频繁。

13.3.3 操作舵机注意事项

单片机的驱动能力有限,所以当需要控制1个以上的舵机时需要外接电源。一个机械臂或者机器人经常需要很多个舵机同时工作,此时需要加一个舵机控制板,舵机控制板本身是一个单片机,它不但能连接16/24/32个舵机,同时也简化了舵机操作命令。

上例中使用的是9g的小舵机,使用单片机上的5V供电,大的舵机有的需要外部供电才能驱动,外接电源时需要降到舵机指定的电压,否则会烧坏舵机。

一般舵机只能在一个方向上旋转90度或180度,如果想前后左右转动,需要使用多个舵机。

如果使用机械爪,需要注意它的旋转范围,如果范围在90度以内,注意将正向负向移动范围设置在-45度到45度之间,以免损坏硬件。如图13.5所示,舵机的齿轮与机械爪的左侧齿轮连接,舵机转动通过左侧齿轮带动右侧齿轮,实现机械爪的开合效果。

实验时千万注意不要夹到手指。

图13.5 机械爪与舵机连接图

课后练习:

练习二:结合上面的例程,实现用游戏摇杆控制舵机。 (提示:为避免损坏舵机,可以在调用angle时设置固定角度,如:负30度)

13.4 思维训练

13.4.1 机器人和人工智能技术

有一天,美术老师让同学们画机器人,在2019年的小学里,大多数同学想到的还是方头方脑,说话声音奇怪,以轮代步的“古代”机器人。实际上,现在的机器人长这样:

图13.6 现代机器人

机器人不仅能够发出甜美的声音,还能通过训练模仿熟人的语音。虽然它还不能取代人类的大多数工作,但也早已不是指哪儿打哪儿的傀儡。

AI是英文Artificial intelligence的缩写译为人工智能,它以学习人类的能力为主,目前已经在很多领域取得了成功:棋牌游戏、图像识别、翻译、写作、判断力、推理能力很多方面机器都已经超越了普通人类,并且还在不断发展。

近两年,通用人工智能AGI也开始成为发展方向,它研究一种通用的能力:让识别人脸的能力可以转化为识别物品;把在棋盘上学到的知识推广到其它领域,具备举一返三的能力。科学家们预言,AGI将在未来10到200年之间正常上线工作。

我们的时代已不同以往,技术革新不再以年为单位,几乎每月,甚至每周都有新技术产生。未来,很多的工作都将被机器取代,很难找到一个不会被机器取代的行业,甚至是创造性的工作。

13.4.2 新科技引起的变化

在发明了耕作机器之后,人类从繁重的体力劳动中解放出来,同时也引起了肌肉的退化;现今,机器和算法取代的不仅是我们的体力,还可能是我们的智力。

这几年,有不少有关导航引起事故的新闻报道:比如《日本游客盲从GPS导航指示把车开进大海》、《为什么盲目相信导航, 一不小心开进了沟里》。在开车时,在自己判断和机器导航之间,屡屡发现我们的判断不如机器,为了更好地解决问题,就会转向依赖导航——人总会选择那些又快又好的解决方案。

然而,过于依赖机器,人的判断就会退化,当人们决策慢慢依赖手机上的新闻、网上搜索的资料、搜索引擎的排名,这些会不会带来误导,操作人的情绪,让人做出错误的决策,以致于逐渐失去判断能力?那时,机器与人到底谁才是指哪打哪儿的傻瓜?

之前的每一次科技进步都带来了更多的工作机会,工业革命之后,大量农民通过简单地培训就能在工厂里工作,但是人工智能需要完整的知识体系,收银员被自动结帐替代之后,无法通过简单培训就成为实验室里的研究员。因此,终生学习变得尤为重要,现在的学习资源相比以往也更容易获取,比如网上教学,视频、论文;相对学习方式,目标更加重要。

当机器在一个又一个领域超越人类,人们开始想象如果有一天机器变成更加智慧的物种,是否将威胁到人类。但是从另一个角度看,人机大战中,战胜李世石的并不只是机器本身,更是机器背后David Silver带领的AlphaGo团队。开发机器智能的人也可以控制机器智能。机器与人之间不是竞争关系,更是协作关系,人机协作将创造更多的可能性。

13.4.3 从人工智能中学习

目前,机器常常在视觉、语言等专门的领域处于优势,而在相对复杂,涉及问题较多的领域表现平平。比如,抓取物体是人从小就具备的能力,而机器人却很难做到。

日本正在开发一种服务机器人来模拟人的工作,其过程相当复杂,比如从冰箱里取一瓶水放在桌子上,需要分解成打开冰箱、抓取、运送、放置;背后还需要机器视觉识别冰箱、水、桌子,从二维影像构建三维空间;识别障碍、规划抓取和行走路径;如果遇到意外情况的安全处理,确认每一步都正常完成,以及各个部件之间协同工作等等。尽管艰难,但仍在不断前行。

目前人类还是比机器更加复杂,科学家通过对人类智能的研究和模拟,把冷冰冰的机器训练出了人类能力和感觉,在分析人类智能的过程中,也发掘出更多人类学习思考的原理和方法:预训练和调优、泛化、迁移、对抗……这些方法同样也可以用于改造人的学习过程,从而加强人的能力。

13.5 小结

13.5.1 单词

本讲需要掌握的英文单词如表13.1所示。

表13.1本讲需要掌握的英文单词

13.5.2 习题答案

1. 练习一:寻找生活中的机器人,比如:玩具机器人,商场医院银行的服务机器人,扫地机器人,或者网络上的图片。分析:它的软件和硬件方面使用了哪些技术,有几个自由度。

图13.7 商场导购机器人

这是商场里的导购机器人,有两个自由度,以控制它的“头”上下和左右转动,在交流时追踪人脸。它有语音问答功能,可以回答,“厕所在哪里?”,“商场里有没有麦当劳”等问题,在找不到麦当劳时,还可以推荐其它的快餐。

2. 练习二:结合上面的例程,实现用游戏摇杆控制舵机。

01 import pyb 
02 
03 pin_x = pyb.ADC(Pin('X5')) 
04 servo_1 = pyb.Servo(1) 
05 led_3 = pyb.LED(3) 
06 led_4 = pyb.LED(4) 
07 
08 while True: 
09     v = pin_x.read() 
10 if v > 3000: 
11         led_3.on() 
12         led_4.off() 
13         servo_1.angle(40,300) 
14 elif v < 2000: 
15         led_3.off() 
16         led_4.on() 
17         servo_1.angle(-40,300) 
18 else: 
19         led_3.off() 
20         led_4.off() 
21         servo_1.angle(0,300)

程序运行效果如图13.8所示。

图13.8 控制机械爪抓取物体­



少儿Python程序第十二讲:单片机控制数码管

少儿Python程序第十二讲:单片机控制数码管

本讲继续学习用Python控制单片机,并用单片机连接和控制其它硬件,具体目标是利用开发板控制四位数码管,显示指定的数字。实验效果如图12.1所示:

图12.1 单片机控制四位数码管显示数字

注意:请先把上一节的例程及练习做完,打好基础,再学习本课内容。

12.1 硬件

本例的难点在于:新增加了一些硬件、连接比较复杂、代码较长、逻辑也相对复杂,需要控制数字到显示的转换。实验需要的硬件包括:

  • TPYBoard V102开发板(单片机)。
  • 5461AS四位共阴数码管。
  • 面包板一块。
  • 200欧电阻四个。
  • 连接线:10条公对母、10条母对母。

12.1.1 数码管

数码管是一种半导体发光器件,其基本单元是发光二极管。数码管的每个数字由七段发光二极管组成,另外一个显示小数点。通过控制每一段二极管是否点亮组成不同的数字。用a,b,c,d,e,f,g,h八个字母代表对应位置的二极管,如图12.2所示。

图12.2 数码管图示

一般情况下,点亮一个发光二极管需要一正一负两条连接线,那么显示四个数字,每个数字由八位发光二极管组成,则需要连接非常多的数据线。数码管简化了连线,一般只需要12条连接线,其中八条控制显示的具体数字,另外四条控制当前操作的是四个数字中的具体哪一位数字。

数码管后面排针连接开发板,接收来自开发板的控制信息,本例中使用的5461AS四位共阴数码管引脚顺序如12.2所示。

注意:由于各厂商硬件不同,不同型号数码管的引脚位置可能存在差异。

12.1.2 面包板

面包板上有很多小插孔,专为电子电路的无焊接实验设计制造。各种电子元器件可根据需要随意插入或拔出,免去了焊接,节省了电路的组装时间,主要用于电路的组装、调试和实验。

面包板的板底有金属条,当元件插入孔中时与金属条接触,从而达到导电的目的。比如中间区域相连的五个孔相互纵向导通,上下方区域横向导通,如图12.3所示:

图12.3 面包板连通示意图

12.1.3 电阻

电阻器简称为电阻,是一种限流元件,将电阻接在电路中后,可限制通过它所连支路的电流大小。电阻器的阻值是固定的,一般有两个引脚,如图12.4所示:

12.4 电阻

实验一般购买“电阻包”,几元钱可购买不同阻值的几百个电阻。可以看到电阻上带有色环,根据不同颜色及其排列方式可判断电阻大小。

计算电阻值先要确定色环的顺序,比如对于一个五道色环的电阻而言,第五环和第四环之间的间隔比第一环和第二环之间的间隔要宽一些。五环电阻的第一、二、三环分别代表三位有效数的阻值;第四环代表倍率;第五环代表误差。具体颜色对应如表12.1所示:

表12.1 电阻色环颜色对应表

例如:如果色环依次为“黄紫黑黑棕”,前三位有效数字为470,第四位100,因此,470*100=470,电阻为470欧姆,允许偏差为正负1%。

网上也可以找到根据颜色计算阻值的计算器,如:
eeworld.com.cn/tools/5s

课后练习:(练习答案见本讲最后的小结部分)

练习一:利用电阻的色环计算几个电阻的阻值,并使用本小节中的网址验证计算结果是否正确。

12.1.4 连接线

连接线用于连接各个电子元件,连线的接口需要与元件匹配。接口分为公头和母头,公头为针,母头为孔,连接线分为以下几种:公对公、母对母、公对母,如图12.5所示:

图12.5 连接线

图中从上到下依次是:公对母线、母对母线、公对公线,以及专供面包板使用的公对公连接线。

12.1.5 硬件连接

X1-X8针连接数码管的a-h排针用于控制每个数字对应的8位发光二极管是否点亮,Y1-Y4针串联电阻后分别与数码管的1-4排针连接,用于指定当前信号是控制四位中的哪一位数字。

请读者按图12.6连接各个元件。

图12.6 数码管接线图

12.2 编写代码

代码较长,因此将其分成三部分:初始化、绘制数字、控制程序。请认真阅读代码及对应说明,理解每一句代码。本节代码较长,注意不要输入错误。

12.2.1 初始化

第一部分初始化。

01 from pyb import Pin
02 import pyb
03 x_pin = {}
04 for i in range(1,8):
05     key = 'X'+str(i)
06     x_pin[key] = Pin(key, Pin.OUT_PP)
07     x_pin[key].high()
08  
09 y_pin = {}
10 for i in range(1,5):
11     key = 'Y'+str(i)
12     y_pin[key] = Pin(key, Pin.OUT_PP)
13     y_pin[key].high()

第01行引入硬件控制pyb模块的Pin类,用于在程序中操作排针。
第02行引入pyb模块。
第03-07行建立字典x_pin用于控制排针X1-X8。
第04行用循环方式分别将1-8赋值给变量i。
第05行每次循环生成变量key:X1、X2……X8
第06行每次循环给字典添加一个键为key,值指向排针的元素,其中OUT_PP指定建立方式为向排针输出数据(而非从排针读入数据)。
第07行将该针置为高电平。

同理,第09-13行建立字典y_pin用于控制排针Y1-Y4。

电流从高电平引脚流向低电平引脚,由于X1-X8,Y1-Y4都被设为高电平,因此,初始化之后无电流流过,因此没有数字被点亮。

12.2.2 绘制数字

第二部分用于向数码管发送不同的信号以显示不同数字,其中定义了draw函数用于绘制每一位数字。

01 num = {}
02 num['0'] = '11111100'
03 num['1'] = '01100000'
04 num['2'] = '11011010'
05 num['3'] = '11110010'
06 num['4'] = '01100110'
07 num['5'] = '10110110'
08 num['6'] = '10111110'
09 num['7'] = '11100000'
10 num['8'] = '11111110'
11 num['9'] = '11110110'
12  
13 def draw(idx, n):
14     for i in range(1,8):
15         key = 'X'+str(i)
16         x_pin[key].low()
17     for i in range(1,5):
18         key = 'Y'+str(i)
19         if idx == i:
20             y_pin[key].low()
21         else:
22             y_pin[key].high()
23     for i in range(1,8):
24         key = 'X'+str(i)
25         if num[n][i-1] == '1':
26             x_pin[key].high()

第01-12行建立字典,字典中的键是被绘制的数字,值是长度为8的字符串,字符串的每一位对应八位数码管的每一个发光二极管,例如:显示数字0时,abcdef位置点亮,而中间的g位置和后面的小数点h位置不亮,因此,对应的字符串为“11111100”。 每个数值依次对应图12.2中的a-h。
第13行定义了单个字母绘制函数draw,函数提供两个参数,第一个参数用于指定绘制哪一位数字,第二个参数用于指定绘制的具体数字0-9。
第14-16行是复位操作,将X1-X8置为低电平。
第17-22行判断设置的是哪一位数据,将被设置的位置设为低电平。
第23-26行从num字典中取出具体数字对应的发光二极管亮灭的字符串,并将需要点亮位置对应的针置为高电平,此时位置idx中对应位置的发光二极管被点亮。

12.2.3 控制程序

本例中控制程序显示“4278”四个数字,由于每次设置只能显示一个数字,如果需要四个数字同时显示,则需要不断循环点亮四个数字,利用视错觉看到LED灯同时点亮的效果。设置每次显示的时间间隔为0.002秒,显示四个数字约0.01秒左右。人眼每秒钟能识别约三十张图片(30帧),识别每张图的时间约0.03秒,由于显示速度比人眼识别速度快,所以人眼看不到LED灯的亮灭变换。

下面程序利用不断循环的方法,将四个数字依次设置到对应的位置。

01 show_str = '4278'
02 idx = 0
03 while True:
04     draw(idx+1, show_str[idx])
05     pyb.udelay(2000)
06     idx = idx + 1
07     if idx >= 4:
08         idx = 0

第01行将需要显示的数字4278赋值给字符串变量show_str。
第02行创建变量idx用于指定显示第几个数字。
第03行建立循环不断写入四个数字。
第04行调用draw 函数写入具体的数字。
第05行的udelay使程序阻塞2000微秒,1微秒= 0.000001秒,2000微秒=0.002秒。
第06-08修改idx,使得idx从0-3循环变化。

课后练习:

练习二:用数码管显示“ABCD”。

12.3 思维训练

这一讲中的实验需要大量插线,虽然没有复杂的逻辑,但工作过程比较复杂。动手尝试很重要,不需要一次插对所有部件,所以看到有一个数码管点亮时,无论它显示正不正确,都是一个进步。然后再基于当前的状态逐步改造。

解决复杂的问题时,首先需要把大问题切分成小块的“子问题”,然后逐个解决子问题,最后还需要考虑子问题之间的相互作用。问题复杂,解决问题的过程也比较复杂。

对于解决复杂的问题,做笔记是非常重要的习惯。当步骤变多,有时需要上网查资料,找到答案后一定要记下来。可以用纸的笔记本,手机上记事本App,或者云端记事本(如:有道云笔记),无论使用什么方法,重要的是记录过程。另外,需要注意:一定要记录清楚,不仅自己能理解,也要让其他人可以看懂,尤其是低龄儿童。

12.3.1 意志力

很多人在童年阶段尝试过多种兴趣班,有的半途放弃,有的花了几年时间学习。在这个过程中到底得到了什么,或者想得到什么?家长可能有以下几种想法:万一是世界冠军的材料,别把孩子耽误了;培养一个兴趣爱好或者一技之长;开阔眼界;太闹在家待不住;或者只是因为周围的人都在学……这几年提倡快乐教育,强调兴趣的重要性,那摔倒了是需要爬起再继续?还是换一条相对好走的路呢?

大多数孩子并不是通过从小的训练,就能成为画家或者运动员,当面临多次挫败,被老师骂成狗,还能再一次调整自己,并且坚持下去,就培养起了一种意志力模式,它可能比学习的知识本身更加重要。之后遇到同等困难的时候,相比没训练过的人更容易克服。

20世纪60年代,斯坦福大学的科学家进行过一个非常著名的意志力实验:规则是把4岁儿童带进一个房间,告诉他们可以马上吃掉一块糖,或者稍等几分钟吃掉两块糖,然后测试人员离开房间,看孩子是否能抵御糖果的诱惑。并进行跟踪记录,当这些孩子上了高中之后,评价这些孩子的成绩、维持友谊能力和处理重要问题的能力,实验的结果是:最后得到两块糖果的孩子SAT成绩平均高出210分,并且在朋友中间也更受欢迎。自控力让他们受益一生。

在高智商和高自控力之间,通过自控力更容易预测一个人在下一学期的表现。如果一个人足够自律,则更加可控。在漫长的成长过程中,自律比智商更加重要。

那么是不是有人生来就有钢铁般的意志力呢?近年来科学家开始研究意志力相关的问题,他们发现意志力不是一种技术,而是一种力量,和肌肉力量一样,也是有限的资源,使用太频繁则会枯竭。在使用意志力的时候也需要注意:不要同时做太多消耗意志力的事,也不要设置超越意志力范围的计划。同时,意志力像肌肉一样,也是可以被塑造的能力。

12.3.2 做计划

培养意志力需要漫长的过程,在意志力不够强大时,也可以通过制定合理的长短期计划达成较好的效果。

生活中没有长期计划,只有短期计划,应付眼前的问题,是大多数小孩,以及不少成年人的做法。当有可能出现棘手的问题,或者令人尴尬的情况,很多时候,我们选择不去想,或者绕开不做。但更好的方法是做出相对的预案。

星巴克有着非常完善的员工培训方案,将有可能遇到的问题和解决方案直接写入员工手册,比如遇到客户的刁难应该如何处理?这使得每个员工无论能力高低,都能很好地应对突发情况。什么东西会伤害到你?通常是全力以赴也解决不了的问题。机遇难以控制,当我们培养起长视的习惯,多设想一些可能遇到的问题和解决方法,通过借鉴,学习,事先用大量的时间准备,即使遇到不如意的情况,反应也不那么狼狈。从而做得更好。

做计划的视角,类似于第10讲中分析问题的角度,需要在不同的层面,做多个计划。在不熟悉的情况下,最好先做一些具体的短期计划,这样即使无法达成最终目标,也能在过程中有所收获。长期计划,可能需要几个月至几年的时间才能实现。这个过程中会遇到各种问题,其它事情的干扰,与其它计划的冲突……因此,长期计划不需要制定得过于详细,在中途也需要不断调整。

12.4小结

12.4.1单词

本讲需要掌握的英文单词如表12.1所示。

表12.1本讲需要掌握的英文单词

12.4.2习题答案

  1. 练习一:利用电阻的色环计算几个电阻的阻值。

(1) 电阻色环顺序:棕棕黑棕棕=110101=1100欧姆
(2) 电阻色环顺序:红紫黑棕棕=270101=2700欧姆

  1. 练习二:用数码管显示“ABCD”。
01 from pyb import Pin
02     
03 x_pin={}
04 for i in range(1,8):
05     key='X'+str(i)
06     x_pin[key]=Pin(key,Pin.OUT_PP)
07     x_pin[key].high()
08  
09 y_pin={}
10 for i in range(1,5):
11     key='Y'+str(i)
12     y_pin[key]=Pin(key,Pin.OUT_PP)
13     y_pin[key].high()
14  
15 num={}
16 num['A']='11101110'
17 num['B']='11111110'
18 num['C']='10011100'
19 num['D']='11111100'
20  
21 def draw(idx,n):
22     for i in range(1,8):
23         key='X'+str(i)
24         x_pin[key].low()
25     for i in range(1,5):
26         key='Y'+str(i)
27         if idx==i:
28             y_pin[key].low()
29         else:
30             y_pin[key].high()  
31     for i in range(1,8):
32         key='X'+str(i)
33         if num[n][i-1]=='1':
34             x_pin[key].high()
35             
36 show_str='ABCD'
37 idx=0
38 while True:
39     draw(idx+1,show_str[idx])
40     pyb.udelay(2000)
41     idx=idx+1
42     if idx>=4:
43         idx=0

建议先逐行读懂例程再做练习,理解是修改的基础。

少儿Python编程_第十一讲:控制单片机

本讲通过操作单片机上的LED灯以及加速度传感器,学习如何使用Python控制单片机,以及连接、调试的方法。

11.1 单片机

单片机一块小芯片上实现完整的小型计算机系统,一般包含主板、处理器(CPU),内部/外部存储设备,可连接各种输入输出设备,它体积小、结构简单、低能耗、价格便宜、并且可编程,常被用于工业控制、家用电器、医疗设备等领域。

单片机在物联网设备的通讯和控制方面也起着重要的作用。物联网是物物相连的互联网,按约定的协议,通过网络使设备与设备相连,进行信息交换和通信,以实现智能化识别、定位、跟踪、监管等功能。

目前流行的单片机有树莓派(Raspberry Pi)、Arduino、51单片机等等,树莓派更像是一台真正的计算机,它功能强大,能耗较高,价格也较贵;Arduino类的单片机便宜、型号多种多样,支持用C语言编写程序;51单片机开发比较底层,相对较难。

早期的单片机主要使用汇编语言和C语言程序控制,使用起来难度较大,学习时间长。随着近年来单片机技术的日趋成熟,目前也有一些支持Python语言的单片机,使用MicroPython开发,MicroPython是Python 3的精减版本,常被运行在微控制器上,除了Python核心库,它还提供模块访问底层硬件,使用方法和Arduino非常相似。

11.1.1 单片机的功能

在学习使用单片机之前,先看看单片机能做什么。单片机主要用来控制其它硬件设备,通过编写程序让多个硬件设备协同工作。

例如制作温控小风扇:用单片机连接温度传感器和小风扇,当温度到达28度时启动风扇,当温度低于28度时关闭风扇。

又如避障(自动躲避障碍)小车:用单片机连接驱动轮和距离传感器,程序判断:当从传感器读出距离小于一定数值,即有障碍物时,停止前进,并控制左右两轮向不同方向旋转实现转向,程序再判断距离,直到前方无障碍后,控制驱动轮继续前进。

11.1.2 购买硬件

一般单片机的售价从几元到几十元不等。支持Python的单片机有:Pymagic、Pyboard、TPYBoard、树莓派等等,本例中选择的硬件是TPYBoard-v102-python开发板,TPYBoard价格不高,且包含详细的中文资料,v102型号的单片机约手掌大小(64mm X 54mm),排针较多(可连接更多硬件),板上自带4个LED灯和加速度传感器,在不连接其它硬件的情况下也能做一些实验。它使用USB线与电脑相连,支持MicroPython语言,文档详见:
docs.tpyboard.com/

除了购买单片机以外,一般还需要购买基本的实验设备:连接线、面包板、发光二极管(小灯)。进阶过程中,根据不同类型的实验,还可选购如数码管、传感器、机械臂、小车、机器人等设备。

11.1.3 单片机介绍

本讲实验中使用的硬件TPYBoard-V102单片机(后文中称为开发板)。如图11.1所示,该开发板由以下部分组成:

图11.1 TPYBoard V102示意图

TF卡槽:用于插入TF卡(一般的手机数据存储卡),TPYBoard自带1024KB的存储空间,其中一部分可以用来存储开发者编写的程序,当程序和数据量较大时,可将程序和数据存储在TF卡上(支持最大8G的TF卡),在插入TF卡时,单片机会优先运行TF卡中的程序。

  • USB接口:开发板通过USB线与电脑连接。
  • 复位键:复位RST全称 RESET,用于重新启动单片机,从头开始执行单片机上的程序。
  • 用户键:用户键USR,也称USER,程序可随时检测此按键的状态,用户可通过此按钮与程序交互。
  • LED灯:TPYBoard-V102提供了红绿蓝黄四个LED灯,其中红灯是状态灯,计算机向单片机写入程序时红灯闪烁,四个LED灯都可以用程序点亮和熄灭。
  • 加速度传感器:加速度可检测X/Y/Z三个方向上的速度变化,并转换成可读的输出信号供单片机上的程序读取。
  • 主控芯片:TPYBoard-V102的主控芯片的型号是STM32,它是单片机的心脏。
  • 排针:排针用于连接其它元器件,在学习阶段请尽量选择排针较多的单片机,以便同时连接更多的元件,比如控制小车时,可能需要连接多个传感器和多个车轮,排针太少无法正常连接。
  • SWD接口:SWD接口由四个排针组成,用于程序调试。

一般单片机都包含上述部件,有些功能强大的单片机还集成了更多的元件和功能。

课后练习:(练习答案见本讲最后的小结部分)

练习一:说说你对单片机和物联网的理解,举几个生活中的例子。
练习二:请向你的朋友介绍一下TPYBoard-V102单片机。

11.2 连接硬件

本讲中的实验只需要电脑、数据线和开发板,无需其它硬件,用数据线将开发板和电脑相连,正常连接之后,可以看到开发板被识别为电脑的U盘TPYFLASH,如图10.2所示:

图11.2连接电脑和开发板

打开TPYBFLASH设备后,可以看到其中包含四个文件:

  • boot.py:在开发板启动时运行的程序,设置了开发板的多个选项参数。
  • main.py:在开发板上运行的主要Python程序。
  • README.txt:说明文档
  • tpybcdc.inf:Windows驱动文件,用于配置串行USB设备。

其中main.py最重要,编写的程序存储在该文件中。

11.3 点亮LED灯

本小节用示例的方式介绍控制开发板上开关LED灯。前几讲学习过编辑Python文件的方法,由于Python代码是一种文本文件,因此,最方便的方法是使用Windows自带的记事本工具编辑,在main.py文件上点击右键,并选择“用记事本打开该文件”,即可修改文件内容。也可以使用Spyder或者Jupyter Notebook编写Python程序。

建议使用Spyder编辑器,从Windows开始菜单打开“所有程序”->Anaconda3->Spyder,并在Spyder界面中打开main.py文件(方法:左上角菜单File->Open,然后打开TPYBoard盘中的main.py文件),将文件修改成以下内容,然后保存文件(保存方法:左上角菜单File->Save)。

01 import pyb 
02 
03 pyb.LED(2).on() 
04 pyb.delay(200) 
05 pyb.LED(2).off() 
06 pyb.LED(3).on() 
07 pyb.delay(200) 
08 pyb.LED(3).off() 
09 pyb.LED(4).on() 
10 pyb.delay(200) 
11 pyb.LED(4).off()

第01行,导入pyb模块,该模块用于控制开发板。
第03行,使用on方法开启第二盏LED灯。
第04行,让程序阻塞200ms,1毫秒=0.001秒,200毫秒=0.2秒。
第05行,使用off方法关闭第二盏LED灯。
第06-11行分别开启和关闭第三盏和第四盏灯(例程没有开关第一盏红色灯)。

保存时,开发板上红灯亮起,等待红灯熄灭后,按下开发板上的RST按键重启开发板,此时可以看到,开发板上的绿黄蓝三色LED灯依次亮起。开发板断电再通电后,四色灯仍然依次亮起,这说明程序main.py已写入开发板。

注意:必须等到红灯熄灭后再按重启按键,否则可能写入失败,数据将被清除(main.py将被重置成出厂状态)。

课后练习:

练习三:写程序使三个LED灯不断循环点亮。(提示:利用while或for循环)

11.4 读取传感器数据

本例程用于读取加速度传感器的数据,并根据开发板角度变化的强度开关LED灯,当变化强时开启第三盏灯,变化较弱或者角度不变时关闭第三盏灯。

01 import pyb  
02  
03 accel = pyb.Accel()  
04 light = pyb.LED(3) 
05 SENSITIVITY = 3 
06  
07 while True:  
08     x = accel.x() # 倾斜越大,x数值越大。  
09 if abs(x) > SENSITIVITY:  
10         light.on()  
11 else:  
12         light.off()

第03行获取加速度传感器的对象并赋值给accel变量。
第04行获取第三盏灯的对象并赋值给light变量。
第05行将变化强度的边界值赋植给变量SENSITIVITY,对于始终不变的值,变量名一般使用大写字母。
第07行使用while循环使程序不断监控传感器状态。
第08行读取传感器x轴方向的变化并赋值给变量x。
第09行用abs函数计算x的绝对值(绝对值的计算方法是:正数和0的绝对值是它本身,负数的绝对值是它的相反数,即去掉负号后的数),并判断其绝对值是否大于强度边界值,如果大于边界值,则认为强度大,执行第10行开启第三盏灯,否则执行第12行关闭第三盏灯。

保存程序,并点击重启按键后,程序被执行。此时用手转动开发板的角度,当角度变化幅度较大时黄灯亮起。

课后练习:

练习四:写程序不断读取加速度传感器x,y,z三个方向的变化值,根据不同变化开关不同颜色的LED灯。

11.5 思维训练

有人需要花比别人多几倍的时间做同样的工作,背单词,做作业,我们可能把它归因于智力问题,或者主观不努力。实际上原因更加复杂,也有很多可以改进的地方。

在信息爆炸的今天,人们面对更多诱惑,电视广告、综艺节目、网络新闻都想放设法地抓住你的注意力;身心合一地坚持做一件事变得越来越困难。其结果可能是放弃困难的工作;或者无法掌握复杂的知识……

我们常常处于心不在焉的状态,听见了,但左耳进,右耳出;写了,但没记住;看起来做了,实际没走心。到底什么是走心?怎么才能走心?首先,要把注意力集中到正在做的事情上来。

11.5.1 监测注意力

最近有一则新闻《小学生戴头环监测注意力引争议》,报道了浙江金华一小学在教学中因使用一款用于监测注意力的头环。被批评“不人道”,“扼杀创造力”。头环的原理是检测学生的脑电波,用以判断学生是否专心,这类产品几年前就已问世,其目的是先关注了解注意力的状态,然后再进一步控制和改进。

一般在一对一的教学中,不用机器也很容易判断学生是否集中注意力,比如在写作业时,一会站起来溜溜,一会上厕所,一会聊天,转笔,晃腿,四处看,从坐姿,眼神都可以观察到注意力的情况……

也有一些时候很难判断是否走神,比如发愣的时候到底是在思考问题,还是想其它事。比思维散乱更麻烦的是:在学习的过程中关注其它事:如果做作业时,总停下来去聊其它的事情,而且聊的都是同一件事,恐怕这件事情现在已经占住了他大部分的精力。这时候,不妨让他自查一下,有几成注意力在当时的“正事”上。

11.5.2 走神的几种情况

思维被占用

如果正在网购,脑子里全是各种各样的商品,这时候开始写作业,想到一会儿还要继续购物,有不少想法,不会把它们全部清空。

这时候很难全神关注地写作业,因为脑中没有足够的空间把作业相关的事都置换进来。如果需要解决一个比较困难的问题,还有可能把思路“拉过来”,如果仅仅是抄写课文,那效果可能非常差,和不写差不多。

保持当前的思维,不被其它后来者占俱,是人的天性,否则任何事都很容易被打断,导致半途而废。当关注一件事的时候,想到的不仅是这件事,还是一个场景(思维背景),相关的东西都被调入内存,有脑子被占满的感觉,这时候思维非常活跃,反应速度也快,是最好的状态。然而人的短时记忆就像计算机的内存,非常有限,不足以容纳太多的内容。我们必须给学习提供足够的时间和空间。

难度过大

在学习一项新技能时,脑的负载非常大,难度越大,负载越大。比如同一部小说,中文版比英文版本更容易吸引人?做不擅长的事情,思维本身就容易被打断,这个词什么意思来着?当不断切换书的内容和单词的意思,读书这件事也变得兴味索然——这是由于来自内部的干扰打乱了原本的节奏,这时可能想做一些其它事缓解或者逃避混乱的状态;此时如果再有来自外部的干扰,就很容易走神。因此,难度越大,越容易走神;基础越差,学习效果也越差。

太过轻松

与难度过大相对的是过于轻松,有时候过于轻松让人觉得无聊,懒散,注意力也会被其它事物吸引。美国心理学博士露西•乔•帕拉迪诺在《注意力曲线》一书中,描述了如11.3所示的注意力曲线。

图11.3 注意力曲线

博士认为只有在强度恰到好处时,注意力才最为集中,当太过轻松刺激不足时,可以通过加入可控的刺激来改善注意力,比如听一些轻音乐,或者适量运动等等。有一些简单的事,的确可以一心二用,比如一边聊天一边走路,也不会撞到树。这是由于走路和闲聊相对容易,因为它们其中一部分已经形成习惯,并不需要大量思考。但是在学习和锻炼新技能时,需要火力全开,不能习惯性地一心二用。

因此,首先要监测注意力,分析当前处于曲线的哪个位置,继而用不同的策略将自己调整到最佳状态。

11.5.3 集中注意力的小技巧

下面提供一些改进注意力的方法:

合理安排时间

尽量先做重要的事,或者需要精力集中的事。很多时候早上的学习效果比下午晚上好很多,早上起床脑子里比较空,白天经历了各种各样有趣的事,到了晚上,就更容易走神,不仅是外界的打扰,也有内部被其它思维打断,往往时间越晚,白天越累,学习效果越差。

控制注意力的方法

借助一些方法,比如使用传统方法控制训练力,用观呼吸、冥想清空大脑,或者使用脑波头环,监督和控制注意力。

快速转换场景

当脑中占满某一件事,又需要转换到另一场景时,建议用手机或者本子把切换场景前需要记住的事记下来。

培养习惯

如果必须几件事一起做,把其中一些练成习惯。

11.6 小结

11.6.1 单词

本讲需要掌握的英文单词如表11.1所示。

表11.1本讲需要掌握的英文单词

11.6.2 习题答案

  1. 练习一:说说你对单片机和物联网的理解,举几个生活中的例子。

单片机可以像计算机一样运行编写的程序,但比计算机更小,运行的程序更简单。
物联网是物和物通过网络连接,不需要人控制就能连接,比如:百度机器人小度可以打开热水器、空调……

2. 练习二:请向你的朋友介绍一下TPYBoard-V102单片机。

参见前文中的“单片机介绍”。

3. 练习三:写程序使三个LED灯不断循环开启和关闭。

01 import pyb 
02 
03 while True: 
04     pyb.LED(2).on() 
05     pyb.delay(1000) 
06     pyb.LED(2).off() 
07     pyb.LED(3).on() 
08     pyb.delay(1000) 
09     pyb.LED(3).off() 
10     pyb.LED(4).on() 
11     pyb.delay(1000) 
12     pyb.LED(4).off()

4. 练习四:写程序不断读取加速度传感器x,y,z三个方向的变化值,根据不同变化开关不同颜色的LED灯。

01 import pyb 
02 
03 accel = pyb.Accel() 
04 v = pyb.LED(3) 
05 g = pyb.LED(4) 
06 k = pyb.LED(2) 
07 C = 3 08 
09 while True: 
10     x = accel.x() 
11     y = accel.y() 
12     z = accel.z() 
13 if abs(x) > C: 
14          v.on() 
15 else: 
16          v.off() 
17 if abs(y) > C: 
18          g.on() 
19 else: 
20          g.off() 
21 if abs(z) > C: 
22          k.on() 
23 else: 
24          k.off()

少儿Python编程_第十讲:数据可视化

少儿Python编程_第十讲:数据可视化

用图表展示数据也被称为数据可视化,图表是将数据表中的数据用图形的方式展示出来,它比具体数值更加直观,尤其是给他人展示时效果更好。统计数据和绘制统计图表也是Python的重要用法。本讲将介绍几种常用的图表绘制方法。

实现Python的数据可视化有很多可选的三方模块,Matplotlib是Python最著名的图表绘制库,它提供大量的工具,可以用于绘制图片、二维或者三维图表,很多绘图模块都基于Matplotlib模块实现。本讲主要介绍Matplotlib模块的使用方法。

10.1 折线图

折线图一般用于显示随时间变化或者有一定顺序的连续数据,比如上一讲使用爬虫抓取的天气预报数据,可用折线图将气温绘制到一张图片中,比数据表看起来更加直观,变化趋势也更加明显。

可使用函数plt.plot绘制折线图,具体方法如下:

01 plt.plot(横坐标列表, 纵坐标列表)

下例用折线图绘制上一讲天气数据中最高气温的变化趋势。

01 import matplotlib.pyplot as plt
02 %matplotlib inline
03                                                                             
04 arr_y = [21, 20, 20, 18, 18]
05 arr_x = ['27日星期三', '28日星期四', '29日星期五', '30日星期六', '1日星期天']
06  
07 plt.rcParams['font.sans-serif'] = ['SimHei'] # 设置中文字体
08 plt.grid(True)
09 plt.plot(arr_x, arr_y)
10 plt.show()

第01行引入了绘图模块matplotlib的子模块pyplot并将其重命名为plt。
第02行只在Jupyter Notebook编程时使用,它用于将绘制的图表显示在网页之中,如果不设置,图表将无法显示。
第04行定义了变量arr_y用于存储最高温度列表。
第05行定义了变量arr_x用于存储日期列表。
程序的最后四行为绘制图表:
第07行将绘图字体设置为黑体“SimHei”,否则无法正常显示中文。
第08行设置在绘图时显示网格。
第09行是具体的绘图语句,它使用了plt提供的方法plot,第一个参数是横坐标显示内容的列表,第二个参数是纵坐标显示内容的列表。
第10行将绘制好的图表显示出来。
程序运行结果如图10.1所示。

图10.1天气预测折线图

课后练习:(练习答案见本讲最后的小结部分)

练习一:下载最近一段时间的地震数据,绘制地震强度变化的折线图。
(“下载最近一段时间的地震数据”可参考上一讲的答案)

10.2 饼图

饼图是一种基本的统计图表。它描述了一组数据中,各个类别占总体的比例。

可使用函数plt.pie绘制饼图,具体方法如下:

01 plt.pie(数据值列表, 显示文字列表)

本例解析天气预报中的天气类型type,统计未来五天中各种天气类型的出现比例,并绘制成饼图。

01 dic_type = {'阵雨': 2, '小到中雨': 1, '中雨': 2}
02 plt.pie(dic_type.values(), labels=dic_type.keys())
03 plt.show()

第01行定义了字典dic_type用于描述各种天气出现的次数:阵雨如现两次,小到中雨出现一次,中雨出现两次。
第02行用plt的pie方法绘制饼图,pie的第一个参数是字典dic_type的具体数值values(),用于设置饼图每个子区域的显示比例,参数labels是每个区域对应的文字说明,设置为字典dic_type的键值keys()。
第03行将绘制好的图表显示出来。

程序运行结果如图10.2所示。

图10.2天气类型统计图

在实际应用时,使用饼图需要注意一些问题。如果类型太少,比如只有两个类型时,直接写出各类型的占比即可,用饼图表示反而画蛇添足;另外,如果类型太多,饼图显示时文字可能重叠,效果也不好,此时可将主要类别显示成图中的区域,占比太少的类别统一归入“其它”。

可以说,饼图比较适合描述两个以上的分类,而类别又不是特别多,且分布相对均匀的分类统计。

课后练习:

练习二:心血管病患人数约2.9亿,其中脑卒中1300万,冠心病1100万,肺原性心脏病500万,心力衰竭450万,风湿性心脏病250万,先天性心脏病200万,高血压2.7亿(摘自《中国心血管病报告2017(概要)》)。根据以上数据绘制饼图。

10.3 柱状图

柱状图也叫条形图,它使用水平或垂直方向柱子的高度来显示不同数值,通过柱与柱之间的关系展示统计效果。柱状图非常灵活,它可以像饼图一样描述不同类别之间的差异,也可以像折线图一样描述连续数据的变化,还可以使用不同颜色的柱子来对比不同情况下的差异。

可使用函数plt.bar绘制柱图,具体方法如下:

01 plt.bar(横坐标列表, 纵坐标列表)

例如:使用柱状图取代饼图,实现上一节中天气类别的统计功能,用下面语句替代上例中的第02行代码。

02 plt.bar(dic_type.keys(), dic_type.values())

程序运行结果如图10.3所示。

图10.3柱状图实例

10.4 直方图

直方图是一种统计报告图,它用柱状图表示数据分布的情况。一般用横轴表示数据类型,纵轴表示分布量的大小。

直方图统计的是连续型数据的分布情况,而饼图统计的是离散型数据的分布情况。比如:天气分类是离散数据,它只有:晴、多云、阴、小雨等几种可能性,而连续型数据由数值表示,它可能是一定范围内的所有数值,包括整数和小数,无法一一列举。因此连续数据不能直接被划分成块。

与饼图的另一个差别是:直方图不需要写程序统计每个类别的实例数,只需将所有数据作为参数传入函数,函数内部自行实现数据统计。

可使用函数plt.hist绘制直方图,具体方法如下:

01 plt.hist(数值列表)

本例使用了上一讲从网络下载地震数据,统计地震等级,并生成直方图。

01 arr = [6.0, 3.0, 3.0, 5.3, 5.5, 6.3, 3.2, 4.5, 3.9, 5.2,
02        4.3, 3.3, 3.3, 6.3, 3.3, 5.8, 5.4, 6.0, 5.5, 3.3]
03 plt.hist(arr)
04 plt.show()

第01行定义了地震等级列表,其中包括20个数据。
第02行是绘制直方图的核心代码,将所有地震等级数据作为参数传给hist函数。
第03行将绘制好的图表显示出来。

程序运行结果如图10.4所示。

图10.4 地震等级分布直方图

作图工具默认将地震等级划分为10个区域,横轴为地震等级,纵轴为符合该等级的实例个数,从图中可以看到,等级在3附近的地震最多,为7例,另外也有大量地震分布在5级到6级之间。

课后练习

练习三:下载最近一段时间的地震数据,绘制其纬度分布的直方图。

10.5 词云图

词云图是一种对文本数据的描述方法,它主要用于统计词在整个文章出现的次数,也叫词频,并用其中出现次数较多的词生成图片,词出现的频率越高,在图片中显示得越大。

制作词云图用到四个Python模块:scipy、wordcloud、jieba、matplotlib。jieba模块主要用于中文分词,在前几讲已经学习过;wordcloud被翻译成词云,它包括词频统计和绘制图片两部分;scipy是Python常用的工具库,此处用到其中的imread读取图片数据;matplotlib用于绘制图表。

下面介绍一种更简单的生成词云图方法——在线生成词云图。

  • WordArt
    |定制性比较强,支持中文,但是图中的词需要手动输入,可通过以下网址访问该工具。https://wordart.com/
图10.5 WordArt示例


图10.6 图悦示例

课后练习:

练习四:使用在线词云图工具,对一段文字提取词云图。

10.6 思维训练

10.6.1 数据分析场景

在大数据领域,把具体工作类型分为:程序开发工程师、数据工程师、算法工程师等等。那么,是不是只有程序员才需要分析数据?并且只需要掌握其中的一部分知识,就能正常工作呢?

从上个世纪,医学生就需要学习医学统计学课程,经济学、制造业也频繁地使用分析工具,无论是做研究还是发表学术论文,数据分析都是必须掌握的技术。

目前,各个领域已基本完成了信息化(用电脑处理数据),拥有大量可用数据之后,大数据逐渐走出了研究领域,得到了更广泛的应用。数据分析技术已应用于预测排队时间、疾病的风险、地震,分析销售数据,设计交通路线。制造、交通、经济、医疗、航天、军事、教育……如今已经很难找到人工智能没有触及的领域。

新一代的技术还在开发:筛选药物分子;在模拟场景之中筛选和测试新材料等等。未来,人工智能和生活将越来越密不可分。就像工业革命之后,大量劳动力从农田走进工厂,从农村搬到城市;信息革命之后,随着教育水平的提高和社会的需要,工作类型也会迎来再次变化。

在很多中小学里,老师给家长的学生成绩分析都使用雷达图表示,如图10.5所示。数据分析已不再是程序员的特有技能,而是像说话、书写、计算一样的普通技能,应用场景举不胜举。

图10.7 词云图

10.6.2 多角度看问题

数据分析不仅给我们提供了函数和作图的方法,更提供了多种看待问题的角度。下面将通过成绩的例子来看看,可以从哪些角度分析问题:假设甲考试成绩为80分,这个分数是高还是低呢?

1.自身比较

  • 横向比较
    横向扩展常常用于序列数据,序列是前一个数据与后一个数据有先后关系的情况,如10.1节学习的折线图,横轴为时间,纵轴为各个时间点的数值。从图中可以看到值与时间的关系,然后根据历史数据来评价当前和预测未来。
    先后关系是一个重要的维度,在得分问题上,画出甲的分数变化时间曲线,可以看到变化趋势,和自己相比,甲的分是比之前的得分高了,低了,还是基本保持不变?
  • 相关性分析
    还有一些特征和成绩相关性较大,也需要考虑,比如是否正常上课,年龄,考试难度等等。

2.个体与整体

个体与他人的比较有以下常用方法:

  • 个体与个体对比
    把甲的成绩和乙的成绩对比,从而看出谁更好,数据量少时,常用这种方法比较,但这种方法有明显的缺陷,常常出现“和正数第一比不了,和倒数第一比还强多了”的情况。
  • 个体与均值对比
    更有效的方法是将甲的成绩与全班的平均值对比。如果高于均值,则说明较好,否则较差。

3.整体比较

整体比较指在两个或者多个组之间进行比较。

  • 分布
    分布是对整体特征的描述,比如一个班平均75分,其中一半同学一百分,另一半同学不及格;另一班平均分也是75分,而所有同学得分都在70-80分之间。这两班学生的平均分虽然一样,但水平也不相同。分布比均值更说明问题,本讲学习的直方图就是常用的分布描述方法。
  • 计数
    计数也是对整体特征的描述,比如除了平均分,还需要考虑有多少人满分,多少人不及格,以及在60-70,70-80等各个区间的人数。

4.不同尺度

纵向扩展描述的是分析问题的粒度大小,对于分数问题,选择分析对象时,可以计算甲这一次考试的成绩,这个月考试的平均成绩,这个学期的平均成绩;或者甲本人的历史成绩、甲所在小组的成绩、所在班的成绩、所在年级的成绩等等。

使用不同的分析单位,不同的尺度,结论也不同。在分析同一问题时,可以在多个尺度提取特征。评价和计划都与尺度相关:尺度太小,只看到眼前;尺度太大,又可能好高骛远,对当前没什么帮助。最好能在不同的尺度上分析问题。

课后练习:

练习五:用思维导图总结分析问题的方法。

10.7 小结

10.7.1 单词

本讲需要掌握的英文单词如表10.1所示。

表10.1本讲需要掌握的英文单词

10.7.2 习题答案

  1. 练习一:下载最近一段时间的地震数据,绘制地震强度变化(震级)的折线图。
01 import matplotlib.pyplot as plt
02 %matplotlib inline
03 import pandas as pd
04  
05 dt=pd.read_html('http://news.ceic.ac.cn/index.html?time=1573369014', header=0)
06  
07 for df in dt:
08     plt.rcParams['font.sans-serif']=['SimHei']
09     plt.grid(True)
10     plt.plot(df['震级(M)'])
11 plt.show()

2. 练习二:心血管病患人数约2.9亿,其中脑卒中1300万,冠心病1100万,肺原性心脏病500万,心力衰竭450万,风湿性心脏病250万,先天性心脏病200万,高血压2.7亿(摘自《中国心血管病报告2017(概要)》)。根据以上数据绘制饼图。

01 import matplotlib.pyplot as plt
02 %matplotlib inline
03  
04 dic_type={'脑卒中':13000000,'冠心病':11000000,'肺源性心脏病':5000000,
05           '心力衰竭':4500000,'风湿性心脏病':2500000,
06           '先天性心脏病':2000000,'高血压':2700000000}
07 plt.rcParams['font.sans-serif']=['SimHei']
08 plt.pie(dic_type.values(),labels=dic_type.keys())
09 plt.show()

3. 练习三:下载最近一段时间的地震数据,绘制其纬度分布的直方图。

01 import pandas as pd
02 import matplotlib.pyplot as plt
03 %matplotlib inline
04  
05 dt=pd.read_html("http://news.ceic.ac.cn/index.html?time=1573369014")
06 df=dt[0]
07 plt.hist(df['纬度(°)'])
08 plt.show()

4. 练习四:使用在线词云图工具,对一段文字提取词云图。

下图为小李同学使用“图悦”工具生成的词云图。


图10.8 练习词.png

5. 练习五:用思维导图总结分析问题的方法。

本题目标是理解和整理思路,答案也比较灵活。下图为小李同学所绘的思维导图。

图10.9 分析方法思维导图

少儿Python编程_第九讲:网络爬虫

少儿Python编程_第九讲:网络爬虫

网络爬虫是指按照一定的规则,自动地抓取网上信息的程序或者软件。一般的爬虫程序是从某一个网页开始,下载(或称抓取)网页内容,同时分析页面上所有的超链接(超链接是一种网页上的元素,它可能是图片或者文字,点击它可打开其它网页),并跳转到其它网页下载内容,再根据新的网页内容跳转和下载,循环往复,直到符合规则的网页都被下载完成。如图9.1所示。

图9.1 网络爬虫示意图

抓取网络数据时,往往需要设定一些规则,比如:只抓取某一网站的数据,设置跳转的最大层数等等。

由于Python支持大量的第三方模块,功能强大并且操作简单,大多数的爬虫程序都使用Python语言编写。

从网络上获取数据一般有两种方式,一种是网站提供接口,供开发者调用;另一种是直接下载网页,然后解析网页内容。9.1节将介绍从接口读取数据的方法,9.2节将介绍解析网页内容的方法。

9.1 抓取天气数据

本节将介绍使用Python程序下载并显示当前的天气数据,代码非常简短,程序如下:

01 import requests 
02 import json 
03 
04 city='北京' 
05 url='http://wthrcdn.etouch.cn/weather_mini?city='+city 
06 resp=requests.get(url) 
07 print(resp.text) 
08 print(json.loads(resp.text))

第01-02行引入模块,requests模块用于从网络下载数据,json模块用于解析下载后JSON格式的数据。
第04行定义了变量city,即指定想要查询哪一个城市的天气信息。
第05行定义了URL(URL详见下一小节),该地址用于查询天气信息。
第06行连接网络,并通过访问URL指定的地址抓取天气数据。
第07行显示网络返回的未经任何处理的天气数据。
第08行解析了返回的天气信息,并将它转换成JSON格式数据。第08行的返回结果如图9.2所示:

图9.2 JSON格式数据

9.1.1 相关知识

网络下载的数据一般都为文本格式,在第七讲中介绍过:文本数据主要由字符组成,不需要特定软件也可查看其内容。网络数据有很多种返回格式,例如:HTML、XML、JSON等,JSON是其中最为简单的格式。

1.JSON格式数据

JSON是一种交换数据的格式,数据量小且便于理解。从上面程序的返回结果可以看到,JSON串的格式类似于Python中的字典,并且是包含嵌套的字典(一个字典中的值是另一个字典)。数据最外层的字典包含三部分:数据data,描述desc,以及状态status;其中第一部分data又分为:对昨天的天气的回顾yesterday,和对未来天气的预测forecast;forecast的内容是一个列表,列表里又包含字典,数据结构层层嵌套。
其最内层包含的是具体的天气数据:日期、最高气温、风力、最低气温、风向、天气类型,格式简单易懂。

2.HTML

HTML是超文本标记语言的简称,相对于只包含字符的文本数据,超文本数据还包含一些符号,通过这些符号可以引入图片、音乐、视频等非文字元素,以及通过排版规则设置更加美观的显示效果。

一般的网页都使用HTML语言编写,在浏览器中点击右键,如图9.2所示,选择“查看网页源代码”,即可看到如图9.3所示的网页源码。

图9.3 浏览器访问网页
图9.4 网页源代码


网页源代码就是编写网页的程序,从图9.4中可以看到,HTML用尖括号作为标记,如“<html>”指定了标记的开头,而“</html>”指定了标记的结尾,标记也可以层层嵌套。

3.URL

URL是互联网上的统一资源定位符,即网上资源的地址。简单的说就是在浏览器上方的地址栏中输入的“网址”,如图9.2中,在浏览器上方输入的baidu.com/。用户通过网址访问网页,就如同通过由文件名和文件组成的路径访问本地计算机上的文件。

常用的URL格式是:

01 协议类型://服务器地址[:端口号]/路径/文件名[参数=值]

例如:https://www.baidu.com,它的协议类型是https,服务器地址是www.baidu.com,中括号中的内容是可选项,在不设置端口号时,使用默认的端口号(端口的概念将在后续课程详细讲解),不指定路径和文件名时,访问该网站的首页。

9.1.2 数据解析

在前几讲介绍Python数据类型时,已经讲解了访问列表和字典元素的方法,本小节作为综合例程,包括定义和调用函数、for循环、访问列表、访问字典、抓取数据、类型转换,复习了本节以及前面学习的知识,并展示访问JSON中具体数据的方法。

下面的程序用于抓取天气数据,并显示返回数据中的日期和最高气温。其中还包含从最高气温的字符串中提取出具体的数字,并将其从字符型转换成数值型。

01 import requests 
02 import json 
03 
04 def show(item): 
05     string = item['high'] 
06     string = string.replace('高温','') # 第二个参数为两个单引号,表示空字符串 
07     string = string.replace('℃','') 
08     string = string.replace(' ','') 
09     print(item['date'], '高温', float(string)) 
10 
11 city='北京' 
12 url='http://wthrcdn.etouch.cn/weather_mini?city='+city 
13 resp=requests.get(url) 
14 j = json.loads(resp.text) 
15 data = j['data'] 
16 show(data['yesterday']) 
17 for item in data['forecast']: 
18     show(item)

程序分成三部分,09行之前为定义用于显示信息的函数,11-14行从网上抓取数据,15-18行为解析和显示数据。
第04-09行,定义了函数show,用于按要求显示日期和最高气温。传入的参数item是字典类型的数据,函数没有返回值。
第05行和09行利用键值(key)分别获取其最高气温high和日期date。
第06-08行使用字符串类提供的方法replace,将字符串中部分字符(第一个参数)替换成另一个字符串(第二个参数),如第06行将字符串“高温”替换成了空白字符串“”,即:从原字符串中去掉了字符串“高温”。
第11-14行,请参见前一例程。
第15行也通过键值的方式取出字典中键对应的值,即数据data部分。
第16行调用上面定义的函数show显示前一天的天气情况。
第17-18行使用循环访问天气预测列表data[‘forecast’],将列表中的每一项作为item,并调用show函数显示其具体的天气情况。

课后练习:(练习答案见本讲最后的小结部分)

练习一:用爬虫抓取百度首页数据并显示出来,百度首页的URL是http://www.baidu.com
练习二:用爬虫抓取你所在城市的天气信息,并显示每一天的日期date和天气类型type(包括天气回顾和天气预测)。

9.2 抓取空气质量数据

从网络上获取的数据以网页为主,练习一中抓取了网页的数据如图9.5所示:

图9.5 网页数据

一般情况下抓取的数据以HTML格式为主,本例中程序返回的数据也是HTML格式。

复习一下,在第七讲中介绍过:Python中使用Pandas模块中的DataFrame存储数据表。本节将介绍使用数据处理的三方库Pandas下载和读取网页中数据表的方法。

例程非常简单:

01 import pandas as pd 
02 dt = pd.read_html("http://www.86pm25.com/city/beijing.html") 
03 print(dt)

第01行导入了pandas模块,并将其重命名为pd。
第02行指定URL,并使用Pandas中的read_html()函数读取该网页中的数据表。
第03行显示下载的数据。

使用浏览器查看该网页的具体内容,如图9.6所示:

图9.6 网页中的表格

可以看到网页中包含一个数据表,其中显示了北京各个地点的空气质量数据。如果不使用Pandas库,需要先下载HTML网页,然后使用字符串处理方法从网页中解析出具体数据,而Pandas库帮助开发者完成了这些工作,程序返回的dt只包含表格的具体数据,去掉了格式信息。程序输出如图9.7所示。

图9.7 解析后的数据表

从方括号可以看出,数据类型是一个列表,它可以支持网页中包含多个数据表,如果存在多个数据表,则每个数据表是列表中的一个元素。通过访问列表中的元素可以得到数据表对应的数据结构DataFrame。

01 for df in dt: 
02     print(df)

本讲涉及的知识比较细碎,抓取每一个网站的方法各有差异,网页可能改版,接口也可能更新,导致原本正常的爬虫程序无法继续使用。但是在数据处理中,抓取数据是不可或缺的部分。另外,需要注意:太过频繁地访问可能引起网站故障,不要影响他人网站的正常使用。

课后练习:

练习三:下载最近一段时间的地震数据,并将数据存入Excel文件。(提示:先用浏览器访问互联网,找一个包含最近地震数据表的网页,使用三方模型Pandas读取其中的数据表,并将其中的DataFrame存入Excel文件)。

9.3 思维训练

9.3.1 决策能力

决策力是一种非常重要的能力,日常生活充满了决策,比如普通人每天在食物上的决定就不止200次,从吃不吃早餐到果酱馅饼还是面包圈,是吃一点还是全吃掉……甚至我们常说的意志力都由大大小小的决策组成:是坚持还是放弃。

决策问题也是人工智能领域最先关注,也是产生成果最多的领域,它包括选A还是选B的二分类问题,包括多个选择的多分类问题等等。机器学习决策的过程,主要是利用之前的数据训练模型,以便在之后遇到类似问题时做出最优的决策。

需要决策的情况,通常是多种选项各占优势的时候,为了行动必须做出选择,而一旦决定,它将压抑其它的想法。重要的决策可能会影响之后很长一段时间的行动。决策有时是基于习惯,有时基于偏好,有时基于推理,有时又会综合考虑各种因素。

有的人有清晰的思维状态:明确表示支持什么或反对什么(尽管不一定对),这可能是由于他习惯快速决定,一旦决定,更倾向于压抑其它的想法;也有人无法驾驭决策本身,常为小小的决定花费大量时间。

决策是经过深思熟虑,还是出于一时兴起?决策本身并没有绝对的对错之分,如何判断决策是否正确?首先,要避免选择恐惧症;同时也要看决策是否促进了目标的达成。

那么如何提高决策能力?对于机器来说,决策模型的好坏主要取决于算法和数据量。机器学习领域有一句话:数据决定了模型的上限,而算法只是努力逼近这个上限。数据量和数据质量非常重要,对人来说,也需要更多的知识和实践来不断训练“决策模型”。

9.3.2 体验失败

我们都希望在整个学习和生活的过程中一帆风顺,幸福快乐,然而真的有持续的快乐吗?如果有什么东西能一直给人提供快感,人们就可能不断地追求它,因此废寝忘食,荒废其它所有的事,像毒品一样。出于自我保护,当一种刺激反复出现时,快乐感觉会逐渐淡化。

成功和奖励非常重要,但对于人类来说,奖励是一种方法,但不是唯一的方法。巴普洛夫的经典性条件反射实验证明动物可以将刺激与旧行为作连接。那么,人们是不是应该更倾向于做简单的事?为什么能解决困难的问题?发明家又怎么能坚持多年试错?计划和解决复杂问题也是人类和高等动物特有的能力。

快乐、成功之外还有一些其它的重要体验。成长过程中一定包含两种学习:应该做什么和不应该做什么。真实世界中并没有像数学公式那样完美的方法,而是充满了例外,因此需要在成功中学习解决问题的方法,在失败中学习各种例外情况。

如果进展并不顺利,陷在问题中的时间越长,驱动力就越弱,脑中的其它竞争者将会更容易获得控制权,这时候就会走神,或者去做其它的事。但是学习任何一门技能,迟早需要忍受一段时间的痛苦感受——克服和坚持的习惯需要在逆境中养成。对于一个已经存在的方法,成功了只是不断重复,失败才需要调整,有更大的进步余地,当然,这个过程中的不舒服也是不可避免的。

9.3.3 偏好

我们可能更愿意去做自己擅长的事,成功的愉悦能带来更大的内驱力。比如某个孩子,长期背诗写作文,因此在学校里明显地比其它的孩子更擅长,而优越感让他更喜欢语文,再把更多的时间投注在这方面。然而,他真的擅长吗?除了努力学习以外,基因,环境等其它条件也很重要。那些没有过多努力和尝试的其它方面,是不是存在更多的可能性?

“喜欢”是一种笼统的感受,有时候,它的存在只是为了关闭其它备选项,让人在举棋不定的时候更容易作出选择。当发现自己非常喜欢某一事物时,需要提高警惕,越是感到喜欢一样东西,越会压抑其它的可能性。“讨厌”也是一种工具,对于难以解决的问题,因为讨厌就破罐破摔的行为,实际上削弱了内部冲突,重建了内心的秩序。我们可能讨厌数学,但学还得上,最终也学会了加减乘除。

整个过程非常复杂,并非一句喜欢或者讨厌就能概括。争取不被情绪操控,反而让它成为一种工具——早日实现情绪自由。

9.4 小结

9.4.1单词

本讲需要掌握的英文单词如表9.1所示。

表9.1本讲需要掌握的英文单词

9.4.2习题答案

  1. 练习一:用爬虫抓取百度首页数据并显示出来,百度首页的URL是http://www.baidu.com
01 import requests 
02 import json 
03 
04 url='http://www.baidu.com' 
05 resp=requests.get(url) 
06 print(resp.text)

2. 练习二:用爬虫抓取你所在城市的天气信息,并显示每一天的日期和天气类型(包括天气回顾和天气预测)。

01 import requests 
02 import json 
03 
04 def show(item): 
05     print(item['date'],item['type']) 
06 
07 city='北京' 
08 url='http://wthrcdn.etouch.cn/weather_mini?city='+city 
09 resp=requests.get(url) 
10 j=json.loads(resp.text) 
11 data=j['data'] 
12 show(data['yesterday']) 
13 for item in data['forecast']: 
14       show(item)

3. 练习三:下载最近一段时间的地震数据,并将数据存入Excel文件。(提示:先用浏览器访问互联网,找一个包含最近地震数据表的网页,使用三方模型Pandas读取其中的数据表,并将其中的DataFrame存入Excel文件)。

01 import pandas as pd 
02 dt=pd.read_html("http://news.ceic.ac.cn/index.html?time=1565082089") 
03 for df in dt: 
04     df.to_excel("test.xls")

少儿Python编程_第八讲:数据库

少儿Python编程_第八讲:数据库

少量的数据一般可以使用数据文件存储,当数据量到达上万行,列也较多时,存储速度就比较慢,一次读出全部内容会占用大量内存,如果只读取部分内容将增加程序的复杂度,查找、插入、删除等操作也会变慢。这种情况下一般使用数据库存储、读写和查询大量的数据。

8.1 数据存储

数据存储种类繁多,比如网络存储、搜索服务、数据仓库、数据库等等。

网络存储是互联网公司推出的在线存储服务,如百度网盘、联想网盘,它们把用户的数据存储在地址位置不同的远端计算机上,存储方法类似于在本地的磁盘上存储数据。通过网络连接让用户高速、方便地使用远程计算机上的存储空间,还有强大的备份功能,保证用户数据安全。

如果把相片存储在自己的手机上,万一手机有一天丢了或者坏掉了,相片也会全部丢失。而存储在服务器端,使用任何计算机或者手机都可以下载,远端的服务器(服务器指较为大型的计算机)一般还提供备份服务,可能一份数据存储在北京的服务器上,备份数据存储在上海的服务器上,万一某天由于火灾、地震等意外情况某一组远端服务器的数据被破坏,备份数据还能使用。当然使用网络存储也需要支付一定的费用。比如百度网盘,存储少量数据免费,存储大量数据按年收费。

搜索服务主要用于文本数据(文字信息)的存储,数据同样可以存储在一台或者多台服务器上,通过对数据建立索引,读写查询文本的速度非常快。

另外,还有数据库和数据仓库,数据库存储的是数据表类的数据,要求事先知道数据的格式,数据库也可以安装在一台或者多台服务器上,其它终端(手机或者电脑)通过程序连接数据库,并将数据存储在数据库中。当数据的格式更为复杂,数据量更大时,往往使用数据仓库存储。

课后练习:(练习答案见本讲最后的小结部分)

练习一:为自己申请免费的百度网盘空间,并在其中备份数据。

8.2 数据库

数据库是到目前使用最多的数据存储方式,数据库的种类也很多,开发者可以根据用途选择适合自己的数据库,比如医院、银行一般使用功能强大且需要付费的Oracle数据库,开发普通网站更多使用免费的MySQL数据库,还有微软的SQL Server数据库,早期数据一般存储在FoxPro数据库中等等。

操作数据库也有一套基本语法,像编程语言一样,它包括对数据库最常用的操作,叫做结构化查询语言,简称SQL。虽然操作每种数据库的SQL略有差异,但基本操作都类似,只要学习其中一种,其它的语法基本都能看懂。

本讲将学习一种最为简单的SQL——SQLite是一款轻型数据库,使用它无需安装数据库服务端程序,也无需配置,占用内存低,处理速度快,使用起来非常方便。

课后练习:

练习二:说说数据库语言和编程语言的区别,列出几种常用的数据库的名字。

8.3 Python访问数据库

程序访问数据库的操作类似于读写文件,主要分为以下几步:

第一步:连接数据库。
第二步:使用SQL语句操作数据库。
第三步:更新数据库。
第四步:关闭数据库。

Python访问数据程序非常简单,先看一段代码。

01 import sqlite3 
02 
03 conn = sqlite3.connect('test.db') 
04 conn.execute('''create table if not exists tips 
05        (name text, 
06        address text, 
07        bill real);''') 
08 conn.execute("insert into tips (name,address,bill) \ 
09        values ('Zhang', 'Beijing', 1004.00 )"); 
10 conn.execute("insert into tips (name,address,bill) \ 
11        values ('Wang', 'Shanghai', 1200.00 )"); 
12 cursor = conn.execute("select * from tips") 
13 for row in cursor: 
14     print(row) 
15 conn.commit() 
16 conn.close()

第01行,先引入了sqlite3三方库,用于支持Python访问SQLite数据库,Anaconda工具集已经安装了sqlite3模块,所以直接导入即可使用。
第03行,在当前目录下建立一个名为test.db的文件作为数据库文件,用于存储数据表。
第04-07行,使用SQL语句创建了一个数据表tips,请注意,由于SQL语句中包含了换行,此处使用了三引号(输入三个单引号)。
第08-09行,向表中插入第一行数据:名字为Zhang,地址为北京,帐单1004。在程序中可以看到,如果某行内容太多,需要换行时,可以使用三引号,或者在行尾加入“\”符号。
第10-11行,向表中插入第二行数据:名字为Wang,地址为上海,帐单1200,由于insert语句一次只能插入一条数据,因此使用了两次insert语句。
第12行,查询表tips中的所有数据,并将结果赋值给变量cursor。
第13-14行,在屏幕上显示返回结果。
第15行,更新数据库。
第16行,关闭数据库。

可以看到,程序中先使用sqlite3.connect ()连接数据库,并得到对象conn,然后用对象conn的execute方法执行SQL语句

程序执行之后生成的数据表如表7.1所示:

表7.1 程序生成的数据表

其中横向为行,纵向为列,表中的第一行是表头,它描述了每一列的作用,在create table时创建,第二三行为具体数据内容,使用insert into语句插入数据库。
一个数据库可以存储多张数据表,数据表就是上一讲学习的网格形式的数据表格。而数据库系统可以支持多个数据库。结构如图8.1所示:

图8.1 数据库结构图

8.4 SQL语言

下面从创建、增、删、查、改几方面介绍SQL语言操作数据库的基本方法。

1. 创建数据表

在使用数据表之前,需要先创建该数据表。SQL语句中的关键字(命令)不区分大小写,即CREATE和create意义相同,但是在大多数据库系统中,库名和表名区分大小写。下例中均使用小写。

新建数据表的语法是:

01 create table 表名称 
02 (列名称1 数据类型, 
03 列名称2 数据类型, 
04 列名称3 数据类型, 
05 ....)

上例中建立的表名是tips,其中包含三列数据:第一列的列名是name(名称),类型是字符串text(类似于Python中的string);第二列的列名是address(地址),类型是字符串;第三列的列名是bill(帐单),类型为实型real(类似于Python中的浮点型float)。
除了语法中必须的关键字,上例中还使用了“if not exists”,它的意思是:如果数据表不存在则创建该表,如果存在则不进行建表操作。

2. 插入数据

插入数据的语法是:

01 insert into 表名称 (列1, 列2,...) VALUES (值1, 值2,....)

上例中向表tips中插入了一行数据,列名和值一一对应。

3. 查询数据

查询数据是最常用的数据库操作,它用于读出表中的具体数据。它的语法是:

01 select 列名称from表名称

可以用“*”表示表中的所有列,即查询表中的所有内容,它的语法是:

01 select * from表名称

还有一种常用的语法是查询适合条件的数据,它的语法是:

01 select 列名称from表名称where列名称 运算符 值

例如,使用以下语句可查询地址为北京的所有数据:

01 select * from tips where address = 'Beijing'

4. 修改数据

修改数据的语法是:

update 表名称 SET 列名称 = 新值 WHERE 列 运算符 值

它可以将表中符合where条件的记录中,某列的值替换成指定的新值。

5. 删除数据

删除数据的语法是:

01 delete from 表名称 where 列名称 运算符 值

它可以删除符合where条件的行(数据库中的行也叫“记录”)。

如果需要删除所有行,可使用:

01 delete from 表名称

或者:

02 delete * from 表名称

6. 删除数据表

删除整个数据表的语法是:

01 drop table表名称

以上介绍了常用的SQL语句,其它SQL语句,可以自行从网上查找使用方法。

课后练习:

练习三:找出本小节开头的程序中所有的SQL语句。

练习四:在SQLite中建立数据表,并填充以下内容,然后查找数据表中数学高于95分的所有行。

表8.2数据表内容

8.5 思维训练

8.5.1 无法言传的技能

大脑中的部件各司其职,它们相互之间只能达到一定程度的协作,而不能也不需要完全相互理解,语言也只是其中的一部分。语言的复杂是因为说话者需要整理脑中的思维结构、转换成语言,并且在听者的脑中构建同样的结构,其中可能涉及很多背景信息。在两人的思维方式或者生活背景类似时,更容易沟通,可能一见如故,人在同类多的环境里也更自在;反之,有人相识多年,却渐行渐远。

很多技能像绘画、演奏、烹调,其中的意会胜过言传,有时技能无法用语言描述,甚至无法解释。“我也说不清为什么这么画,不知当时自己是怎么想到的,手就自动画下来了。”当我们无法拆解、归因、再造、迁移的时候,这项技术就变得很神奇。人们把它归因于“天赋”、“悟性”,也羡慕那些有着超凡能力的人。

当你掌握了绘画、音乐的方法,能用它们表达脑中的世界,并且在他人脑中重建相似结构,引发共鸣,它就变成了你的语言。那么,当机器足够复杂,并接受更大规模训练,也许它也能掌握这门语言。

缺少语言的支持,很多时候老师就难以在学生的头脑中重构与他脑中相同的思维结构,又说不出到底哪里不对。有时,老师也不知道自己是怎么做到的,于是,只能沿用当初自己的学习过程来教导学生。其实通向终点的道路不止一条,同一位老师也不一定能教会每一位学生,如果可以换一位思维匹配度更高的老师,也许就能解决问题。

8.5.2 漫长的平台期

上一讲提到编程至少在初期是渐进式,而非顿悟式。但我们都或多或少地听说过有关“顿悟”的故事,似乎就在某个不经意间,突然开窍了。有些技能不是平滑地上升,而是阶梯式进步,当面对漫长的平台期。坚持了一段时间,也没有太多提高,是否怀疑自己没这个天份,然后放弃?而那些所谓的天赋异禀,又是否只是掌握了一些我们不知道的技巧?

在练字的时候,照着字贴练得还不错,下次不注意又“回去”了。这时候老师家长也很无奈,方法我教了,你也会了,但是怎么不用呢?这就如同:“并不是我知道自己结巴,就不结巴了”,需要通过练习把“知道”变成“习惯”。

为什么不能一学就会呢?在软件升级的过程中,不可能一边运行一边修改。当一个重要软件已经开始正常工作,这时开发它的升级版,新功能的任何小问题都可能影响用户的正常使用,所以一般让新旧软件同时运行一段时间,保证新软件完全正常的情况下再替换旧版本。软件使用的时间越长,复杂度越高,越多其它软件依赖它,它就越难被替换。当新的思维积累到一定程度,慢慢变得成熟,遇到某个时机,就自然替代了旧的方式;看似前期毫无作用,其实是在后台默默地构建和测试。

很多人在童年阶段尝试过多种兴趣班,有的半途放弃,有的花了几年时间学习。在这个过程中到底得到了什么,或者想得到什么?家长可能有以下几种想法:万一是世界冠军的材料,别把孩子耽误了;培养一个兴趣爱好或者一技之长;开阔眼界;太闹在家待不住;或者只是因为周围的人都在学……

也许这个过程正是学习“如何掌握技能”的过程,如果不用足够的时间,足够的难度去学习某一种技能,可能永远都无法掌握复杂的技能。最好有一个相对长时间的计划,在这个过程中即使遇到平台期,也尽量坚持,从中培养学习的方法和学习的习惯。

8.5.3 不断学习

换一种方法,不但涉及大量的学习成本,还可能破坏原本稳定的结构,带来未知的错误,影响正常工作,如果带来的好处又不明显或者不确定,大多数情况下人们都选择保持不变。很多程序员喜欢用文件存储,如果不是数据量实在太大、无法操作,通常不会用到数据库或者数据仓库,也是同样的道理。

古代社会发展非常缓慢,爷爷的生活技能传给孙子同样适用,现代科技成指数形爆发。小时候学的东西,还没等长大可能就过时了。只在上学阶段学习,这种想法已不再适用,这并非制造焦虑。“世界上唯一不变的就是变化”,学习和不断适应就像锻炼身体一样,是一辈子的事。

8.6 小结

8.6.1 单词

本讲需要掌握的英文单词如表8.3所示。

表8.3本讲需要掌握的英文单词

8.6.2 习题答案

  1. 练习一:为自己申请免费的百度网盘空间,并在其中备份一些数据。

第一步:在百度搜索“百度网盘”。
第二步:注册百度帐号,申请免费网盘。
第三步:新建文件夹,并重命名。
第四步:上传相片到新建的文件夹。

2. 练习二:说说数据库语言和编程语言的区别,列出几种常用的数据库的名字。

数据库语言只能操作数据库,编程语言可以编写游戏,控制硬件等等功能更多。
数据库有FoxPro,Oracle,MySQL,SQLite。

3. 练习三:找出本小节开头的程序中所有的SQL语句。

01 import sqlite3 
02 
03 conn = sqlite3.connect('test.db') 
04 conn.execute('''create table if not exists tips 
05        (name text, 
06        address text, 
07        bill real);''') 
08 conn.execute("insert into tips (name,address,bill) \ 
09        values ('Zhang', 'Beijing', 1004.00 )"); 
10 conn.execute("insert into tips (name,address,bill) \ 
11        values ('Wang', 'Shanghai', 1200.00 )"); 
12 cursor = conn.execute("select * from tips") 
13 for row in cursor: 
14     print(row) 
15 conn.commit() 
16 conn.close()

在execute函数中执行的就是SQL语句。

4. 练习四:在SQLite中建立数据表,并填充以下内容,然后查找数据表中数学高于95分的所有行。(小李同学作业)

01 import sqlite3 
02 
03 conn=sqlite3.connect('test1.db') 
04 conn.execute('''create table if not exists tips 
05     (name text, 
06     yuwen real, 
07     shuxue real, 
08     yingyu real );''') 
09 conn.execute("delete from tips") 
10 conn.execute("insert into tips(name,yuwen,shuxue,yingyu)\ 
11         values('zhangsan','81','90','95')"); 
12 conn.execute("insert into tips(name,yuwen,shuxue,yingyu)\ 
13         values('lisi','93','96','97')"); 
14 conn.execute("insert into tips(name,yuwen,shuxue,yingyu)\ 
15         values('wangwu','95','100','100')"); 
16 cursor=conn.execute("select * from tips where shuxue > 95") 
17 for row in cursor: 
18      print(row) 
19 conn.commit() 
20 conn.close()

需要注意:每次插入数据时先要删除数据库中的内容,否则每次执行程序时数据都会被插入一次。

少儿Python编程_第七讲:文件存储

少儿Python编程_第七讲:文件存储

程序和存储密不可分,程序需要的数据、文字、图片都以文件的形式存储在磁盘上,程序处理时需要从磁盘上读出文件,处理之后需要将结果存储到磁盘上,本讲学习如何使用Python程序读写磁盘上的数据。

7.1 读写文本文件

计算机中的文件通常分为两类:文本文件和二进制文件。文本文件是以纯字符方式存储的文件,也是最简单的一种存储格式,二进制文件一般存储数据和指令,无法直接查看文件内容,只能通过特定软件读取和分析的文件,图形和数据一般都存储成二进制文件。

7.1.1 文本文件

文本文件的扩展名通常是“.txt”,使用Windows记事本可以打开该格式的文件,方法是在文件上点右键,并在右键菜单上选择“用记事本打开该文件”。除了“.txt”文件,像Python扩展名为“.py”的代码文件,扩展名为“.csv”的数据文件都以纯文本格式存储,也就是说,都可以使用记事本查看其内容。

英文相对比较简单,使用ASCII码的128个字符,每个字符一个字节(8位),就能存储大小写英文字母、数字以及一些特殊符号,而中文汉字成千上万,编码方法也不只一种,因此,在读写包括中文的文本文件时需要指定字符编码。常用的中文编码有:

  • GB2312/GBK/GB18030
    计算机需要支持不同的语言文字,不同的国家和地区制定了不同的标准,由此产生了 GB2312为简体中文, BIG5为繁体中文, JIS为日文,以及各自的编码标准。这些使用2个字节来代表一个字的编码方式,称为 ANSI 编码。在简体中文系统下,ANSI 编码代表 GB2312 编码,在日文操作系统下,ANSI 编码代表 JIS 编码。Windows记事本默认使用ANSI格式存储。

    GB2312、GBK和GB18030都用于汉字的编码,最早制定的汉字编码是GB2312,包括6763个汉字和682个符号;95年重新修订了编码,命名GBK1.0,共收录了21886个符号。 之后又推出了GB18030编码,共收录了27484个汉字,同时还收录了藏文、蒙文、维吾尔文等主要的少数民族文字。
  • UTF-8
    UTF-8是一种可变长度的字符编码,它用1-6个字节给一个字编码。UTF-8是Linux和高版本Python语言默认的中文字符格式。在编程时,常用到编码转换或者需要指定编码类型的情况。

以上两种是最常用的编码格式,字符编码还有Unicode 8,Unicode 16等等,

7.1.2 保存文本文件

本节介绍用Python程序读写文本文件,写文本文件包括三步:

第一步:打开文件。
第二步:写入内容。
第三步:关闭文件。

例程如下:

01 f = open('test.txt','w',encoding='utf-8') 
02 f.write("123") 
03 f.write("四五六") 
04 f.write("\n") 
05 f.write("789") 
06 f.close()

第01行以写文件的方式“w”打开文件test.txt,如果此文件已经存在,则覆盖该文件内容(之前的内容被新的内容取代),并且指定文件编码为“utf-8”格式。然后向文件中依次写入“123”,“四五六”,“回车换行\n”和“789”,最后使用close方法关闭文件。

写入文件后,用前一节的方法把文件下载到本地并打开,可以看到其内容是:

123四五六 789

需要注意的是:只有写入换行符“\n”时,文本文件中才被加入换行。

7.1.3 读取文本文件

读取文本文件包括三步:
第一步:打开文件。
第二步:读出内容。
第三步:关闭文件。

例程如下:

01 f1 = open("test.txt", 'r', encoding='utf-8') 
02 s = f1.read() 
03 print(s) 
04 f1.close() 
05 # 运行结果: 
06 # 123四五六 
07 # 789

第01行同样是打开文件,不同的是使用读文件方式“r”打开。
第02行用read方法读取文件中的所有内容并将其赋值给变量s。
第03行显示出变量s中存储的数据。
第04行关闭文件。

课后练习:(练习答案见本讲最后的小结部分)

练习一:创建文本文件xxx.txt,在其中写入“我爱北京天安门”,用另一段程序从中读出内容,文件使用“gb2312”编码。

7.2 读写数据表

数据表也是一种重要的数据格式,它以表格的方式存储数据,形如表7.1所示:

表7.1数据表示例

数据是数据分析、数据挖掘的基础,数据一般都存储在这种由行列组织成结构中,称为数据表,数据表横向称为行,纵向称为列。表之间又可能存在各种各样的关系,多个相关的表组一个数据库。

7.2.1 数据表

Windows下的Excel是最常用的电子表格工具。它的界面如图7.1所示:

图7.1 Excel电子表格

Excel表格存储文件的扩展名一般是“.xls”或者“.xlsx”,也可以保存成纯文本格式的“.csv”文件。本节将学习使用Python程序读写Excel格式的数据表。

数据表中的数据比较特殊,包含横向和纵向两个维度,因此,也需要特殊的数据结构存储。Python常使用Pandas三方模块中的DataFrame存储数据表。Anaconda工具集已经安装好了Pandas模块。直接导入即可使用,为书写方便,一般将其重命名为pd。

01 Import pandas as pd

DataFrame是Pandas模块中定义的一个类,可以通过构造函数构造DataFrame,并使用其中的方法(函数)实现各种功能。

构造数据表的方法很多,可以通过字典创建,也可通过列表创建,例如:

01 df = pd.DataFrame([[81,90,95],[93,96,97],[95,100,100]], 
02                   index=['张三','李四','王五'], 
03                   columns=['语文','数学','英语'])

程序创建了一个内容与图7.1相同的数据表,其中01行使用列表定义了数据表的具体内容,列表中有三个元素,每个元素又是一个列表,分别对应每行数据,第02行用列表的方式设置了行索引,第03行用列表的方式设置了列索引。

7.2.2 保存数据表文件

创建DataFrame数据df之后,可将df内容写入数据表文件。

01 df.to_excel("test.xls")

使用数据表的方法to_excel将数据表存储成Excel格式的文件“test.xls”。之前介绍过Jupyter Notebook是客户端/服务端结构,所有的修改都保存在服务端,需要下载到本地才能用软件打开。

执行上面程序之后,在Jupyter Notebook的文件浏览界面可以看到当前目录下增加了“test.xls”文件,选中该文件(选中文件之前的单选框),点击上方的下载按钮(Download),如图7.2所示。选择打开该文件,即可看到图7.1所显示的Excel电子表格。

图7.2下载数据表文件到本地

7.2.3 读取数据表文件

与写数据文件相对应的是读取已经存在的数据文件,方法如下:

01 df1 = pd.read_excel("test.xls", index_col=0) 
02 print(df1) 
03 # 运行结果: 
04 #    语文  数学  英语 
05 # 张三 81 90 95 
06 # 李四 93 96 97 
07 # 王五 95 100 100

第01行使用read_excel方法读取“test.xls”文件,并把它的第一列作为索引列。
第02行将数据表的内容显示出来,运行结果如04-07行所示。

除了使用read_excel/to_excel读写Excel数据表,DataFrame还提供to_csv,to_pickle等方法读写其它格式的数据表文件。

课后练习:

练习二:用百度搜索使用字典创建数据表的方法,并写代码创建本例中的数据表。

7.3 操作文件和目录

对文件的操作除了读写文件以外,还包括复制、移动、删除、创建目录等等,Python的内置模块os提供了这些功能支持。使用这些功能之前需要导入os模块。

01 Import os

1. 创建目录

在当前目录下,建立名为“xxx”的子目录。如果目录已存在,则报错。

01 os.mkdir("xxx")

2. 删除目录

删除当前目录下名为“xxx”的子目录。如果目录不存在,则报错。

02 os.rmdir("xxx")

3. 删除文件

删除刚才创建的名为“test.txt”的文件,如果文件不存在,则报错。

03 os.remove('test.txt')

4. 判断文件或目录是否存在

显示当前目录下是否存在“test.txt”,如果存在,则显示True,不存在则显示False

04 print(os.path.exists('test.txt'))

课后练习:

练习三:在当前目录创建目录“abc”,然后删除该目录。

7.4 CS结构和BS结构

客户端Client/服务器Server结构,简称C/S结构,也叫C/S架构,比如:手机微信就是C/S结构,用户使用时需要在手机或者电脑上安装微信客户端程序,它通过网络与远程的服务器连接,服务器是远程的安装有服务端软件的计算机。收发消息时由客户端先传给服务器,再由服务器端处理和分发给其它客户端,这样多台终端(手机或电脑)协作的方式就是C/S结构。

图7.3 C/S结构示意图

与C/S结构类似的是B/S结构,它不需要在终端上安装软件,只需要使用浏览器连接远程的服务器,即可完成任务。比如:使用Jupyter Notebook编写程序就是B/S结构,可以将Python环境安装在某一台服务器上,其它机器使用浏览器连接服务器即可使用Python环境。B/S结构的优点是只需要配置和管理服务端程序即可,对客户端机器要求比较低。而C/S结构的优点是占用资源比较少,而且使用更加方便,如微信的界面就比手机浏览器更好用。

图7.4 B/S结构示意图

无论是B/S结构还是C/S结构,服务端和客户端都可以安装在同一台电脑上,如上面例程中的Jupyter Notebook的服务端和浏览器就在同一台电脑上使用。

Jupyter Notebook服务端在Windows的存储目录是当前用户存储数据的默认目录,如果使用管理员Administrator登录,则存储在:C:\Users\Administrator目录下。因此,打开Jupyter中的文件有两种方法,使用Download将程序和文件下载之后打开,或者直接在服务端的存储路径中打开。

课后练习:

练习四:在手机或者电脑上,找一个典型的C/S架构程序和一个B/S架构程序。

7.5 思维训练

7.5.1 编程基础

有些小朋友从学龄前就开始学习乐高机器人或者Scratch编程,这些不识字也能学习的编程工具,与程序员编写的程序有多大差别?究竟几岁开始学习编程,什么样的基础可以开始学习呢?

笔者认为,至少需要以下几方面能力:

  • 熟悉计算机、会打字 现在的孩子往往在幼儿园阶段就开始玩手机,对游戏和微信都很熟悉,手机替代了电脑的大部分功能之后,低年龄儿童对电脑的熟悉程度反而不如前几年。在孩子不熟悉键盘的情况下,大量时间用于输入程序(一个字母一个字母找),孩子在找字母的过程中思路常常被打断。 因此,对于键盘打字不仅要会,还要熟悉,建议先花一段时间练习打字。
  • 基本的语文、数学、英语知识 语文方面,至少要掌握常用字,有一定的阅读理解能力,基本能理解书中的文字,会用拼音输入法,会写字,能对学习的重点记笔记。 数学方面,至少会计算加、减、乘、除,在小李同学二年级时和她讨论概率问题,猛然发现她不会除法,再从除法教起,则无法保证学习的进度。 英语方面,至少熟识26个英文字母的大小写,知道什么是单词,掌握简单的拼读方法即可。
  • 理解和逻辑能力 儿童的逻辑能力也是随着年龄增长、学习知识难度增加逐步提高。小李同学二年级时,我教她写循环,在街上她看到可回收垃圾的标志对我说“这个像for循环”,我以为她已经掌握了循环的用法,但当时她却理解不了循环嵌套。我尝试用四五次课的时间教她,但就是教不会,她只能把例程背下来,稍稍换一个场景就不行了。当时的编程课就在这里结束了。一年半之后,她看着文档自己就学会了,几乎没遇到任何问题。

综上,建议孩子在9-10岁,三四年级以上开始学习编程,一方面在很多学校都从二年级开始学习计算机课,三年级的孩子对计算机已经有了初步了解,同时在基础知识方面也有了一定积累。另外,这个阶段孩子逐渐有能力处理抽象和复杂的事务。

7.5.2 层进与顿悟

本讲涉及的主要是一些常用的工具,只要会用即可。它和之前讲的文件系统、上网查资料类似;与逻辑思维、推导并没太大关系。但学到后面其它课程时,就能看到,它是数据处理和网络编程的基础。写程序并不是单纯地学习Python的语法或者思维方法,而是像织网一样,尽量建立程序相关的体系结构。

计算机方面的知识往往有一些共通性,使用Python、Excel、Word、Photoshop、百度搜索或者安装打印机,其中有很多细碎的知识点相互重叠。对计算机接触越多的孩子看起来学得更快,也更加擅长。这就如同从小上英语课外班的孩子不一定是单词默写最好的,但是整体英语水平却明显高于其他孩子。

编程更像是学习数学,还是学习语文?数学给人的印象更偏重于理解,“聪明人”能很快明白;而语文则更偏重记和背,只要功夫深,铁杵磨成绣花针。很多人认为编程更近似于学习数学,但是除了思维方法以外,编程语言和汉语英语一样,也是一门语言。

1.记忆

在学习语言的时候,想读懂一篇文章,需要明白单词,语法,理解每个词在不同环境中的含义。学习编程也是一样,想读懂一段程序,需要理解其中每一个语句,每一个函数的功能,一个语义模糊就可能无法理解整段功能。

因此,第一步是记忆,不能现用现查。一次接触太多陌生的知识,脑力大部分被记忆占用,就没有余地思考。就像一本书有中英文两个版本,肯定是中文读起来更加轻松。

2.使用

母语是最容易掌握的语言,日常看手机、看书、说话,看电视都是学习的过程,几乎不需要思考能就够反应出某个词出现在哪种环境之中,应该使用它的哪个含义。相对来说学英语就困难一些,各种语言之中都有一词多义的问题,尤其是在一句话之中有两个以上不确定含义的单词,就很容易理解错误。读英文文章时,如果生词太多,即使每个词都查了字典,对全句的理解也不一定正确。

不同的语言的结构也不相同,比如时间、地点、被动式、从句,很多语言都有差异,想要学会,要么背下所有规则,还要会用,能快速地使用这些规则;要么通过阅读大量资料来培养习惯。那么如何学习非母语的语言呢?每天上一节英语课,或者每周一次的外教课,背下教科书里的内容,考试达标就可以了吗?毕竟大多数人都没有很好的语言环境。

任何语言都是交流的工具,利用它解决问题也是最好的学习方法,比如用英文阅读就是一种很好的练习方法,即使语言上不能完全理解,还可以借助常识理解文章的意思;此时,词不是孤立地存储在脑中,而是和其它词以及环境建立了联系,从而形成知识网。

任何课上学习的内容都非常有限,编程也一样。程序语言的优点在于并不像中文或者英文有太多需要记和背的词义和结构,尽量这样,仅看一遍书也肯定学不会。尽量多读别人的代码,如果练习题不会做,可以在网上查找解决类似问题的程序段,以及上文中类似的程序,一开始可能是简单地套用,但是训练和积累到一定程度,那些每一次都出现的模型就会在脑中形中统一的框架(套路)。第一次看可能很难,但是类似程序看得多了,也就自然理解了。

可以说,至少在初期,学习的过程不是顿悟式,而是层进式的。因此,每一讲学习的用法和重要单词一定要背下来。

7.6 小结

7.6.1 单词

本讲需要掌握的英文单词如表7.2所示。

表7.2本讲需要掌握的英文单词

7.6.2 习题答案

1.练习一:创建文本文件xxx.txt,在其中写入“我爱北京天安门”,用另一般程序从中读出内容,文件使用“gb2312”编码。

写入文件:

01 f=open('xxx.txt','w',encoding=' gb2312') 
02 f.write("我爱北京天安门") 
03 f.close() 
04 print(f)

读出内容:

01 f1 = open("xxx.txt", 'r', encoding='gb2312') 
02 s = f1.read() 
03 print(s) 
04 f1.close()

2.练习二:用百度搜索用字典创建数据表的方法,并写代码创建本例中的数据表。

01 import pandas as pd 
02 sales = {'name': ['张三', '李四', '王五'], 
03 '语文': [81, 93, 95], 
04 '数学': [90, 96, 100], 
05 '英语': [96, 97, 100]} 
06 df = pd.DataFrame.from_dict(sales) 
07 print(df)

3.练习三:在当前目录创建目录“abc”,然后删除该目录。

01 import os 
02 os.mkdir("abc") 
03 os.rmdir('abc')

4.练习四:在手机或者电脑上,找一个典型的C/S架构程序和一个B/S架构程序。

“淘宝”同时支持b/s和c/s结构,可以用浏览器打开,也可以用手机应用打开。

少儿Python编程_第六讲:函数和类

当需要实现复杂功能时,程序往往包含成千上万行代码,由多个程序员同时编写和维护。如果把程序都放在一起,会非常复杂,并且每位程序员需要读懂所有的代码。

此时可以将整体程序按功能切分成多个程序模块,每个模块可能包含多个程序文件,在程序文件中又可以把代码细分成函数、类,使得逻辑更加清晰,调用更加方便。每位程序员只要完成自己的工作,并将程序封装起来(封装就如同包装,它隐藏了内部编程的细节,只对外暴露接口),其他程序员在需要使用时通过接口调用它,各个模块像搭积木一样分工合作,最终实现复杂的功能。

6.1 函数

函数是把具有特定功能或者经常使用的程序写成简单的程序块,并赋予函数名称,当程序需要使用该功能时,通过函数名称调用程序块。

使用函数的好处在于:

  • 代码可重用,同一功能只需要实现一次,使用时调用其函数名即可。
  • 程序员可以把功能封装到函数内部,其他人使用该功能时只需要调用函数名称,无需关注函数内部具体的实现方法,从而降低了程序的复杂度。
  • 把较长的程序切分成段,使于理解和使用。

6.1.1 内置函数

Python提供大量的内置函数,比如之前使用过的在屏幕上输出的print()函数,用于接收用户输入数据的input()函数,用于转换数据类型的float()函数,以及用于生成列表的range()函数。

使用函数最重要的是:函数名、参数和返回值。函数名是函数的名字,一般根据它的功能命名;参数是调用函数时传给函数的信息;返回值是函数处理之后的结果。

以float()函数为例,它的功能是将其它类型的数据转换成浮点型数据。

01 x = float('2')

其中float是函数名,后面紧跟小括号,括号内是函数的参数,调用float()函数需要提供的参数是待转换的数据,本例中的参数是字符串’2’;函数的返回值是转换后的浮点数2.0,01行中将返回值赋值给变量x。

6.1.2 自定义函数

除了Python提供的内置函数以外,开发者还可以自定义函数。一般使用关键字def创建函数,也叫定义函数,def之后是函数名,然后在小括号内设置参数,再加上一个冒号,冒号之后是函数内的程序块,以空格缩进(一般为四个空格)区分函数中的程序块和函数外的程序块。关键字return的意思“返回”,在函数中遇到return语句时函数将会在此处结束,并返回调用它的位置。

创建函数语法如下:

01 def 函数名([参数1, 参数2, 参数3...]): 
02    程序块 
03    [return 返回值1, 返回值2, 返回值3] 
04 
05 [变量=]函数名([参数1,参数2,参数3...]) # 此处为调用函数 
  • 函数名:开发者根据函数的功能定义对应的函数名,函数命名规则与变量命名规则一样,函数名可由字母数字下划线组成。
  • 参数:开发者可根据需要定义一个参数、多个参数或者无参数。参数用于接收调用函数时传来的数据,如果有多个参数,参数之间用逗号分隔。(注意:在语法说明中,中括号内的内容为可选项,并不是指列表)。定义函数时使用的参数叫形参,是变量;调用函数时使用的参数叫实参,是具体值(可以是常量、变量、表达式)。
  • 程序块:被多次调用的程序写在程序块里。
  • 返回值:返回值用于返回函数执行的结果数据。开发者可根据需要定义一个返回值、多个返回值或者无返回值,无返回值时可不使用return语句,支持多个返回值是Python语言的特色,在返回多个值时,值与值之间用逗号分隔,调用函数时也需要用多个变量接收返回值。
  • 调用函数:在定义和实现了函数的功能之后,使用函数名加参数的方式调用函数。

下面,示例定义一个函数,用于计算矩形面积:

01 def area(w, h): 
02     return w*h 
03 
04 a = area(2,3) 
05 print(a)

在第01, 02行,首先定义了名为area的函数,函数包含两个参数矩形的宽w和高h,并返回w和h相乘的计算结果。第04行调用函数area,传递参数宽为2,高为3,并将函数的返回值赋值给变量a,在第05行显示结果a的值。

课后练习:(练习答案见本讲最后的小结部分)

练习一:用百度搜索几个Python常用的数学函数及其使用方法:求和、求最大值和最小值。
练习二:定义一个函数,计算语文、数学、英语三门考试成绩的平均分,并调用该函数计算小明语文90、数学95、英语80,和小红语文93,数学96,英语97,两名同学各自的平均分。

6.1.3 递归调用

小时候听过一个故事:从前有座山,山里有个和尚讲故事,讲的是从前有座山,山里有个和尚讲故事,讲的是从前有座山,山里有个和尚讲故事……每一个故事里又包含同样的故事,从而引发了无限循环。

类似的,函数也可以调用它自身,也叫递归。例如:

01 def a(x): 
02 if x > 3: 
03     return 
04 else: 
05     print(x, end=",") 
06     a(x+1) 
07 a(1) 
08 # 运行结果:1,2,3,

其中函数a中又调用了函数a,一般递归函数中都有分支用于避免无尽地循环,如本例中的第02、03行所示。使用递归函数需要注意,调用的层次不能太多,否则,即使程序逻辑上没有问题,也会报错。

6.2 类

类是面向对象编程的基础,它是对某一类事物的抽象。只要是学习面向对象的编程语言都需要掌握类的相关概念,除了Python语言以外,常用的面向对象的编程语言还有C++,Java等等。在学习类的用法之前,先学习几个基础概念。

  • 类:类是一个模板,它描述一类对象的行为和状态。比如把鱼定义成一个类,它包括一些状态(变量):鱼的颜色、鱼的长度,以及一些行为(函数):游泳、吃饭、排泄。
  • 实例:实例是类的具体化,有具体的状态和行为。比如金鱼,它的颜色是红色,长度是10cm。
  • 方法:方法是类中的函数,用于实现具体的功能。
  • 构造函数:构造函数是类中的一个特殊函数,它一般在创建类时被调用。Python中的构造函数名为init()。注意init前后都是双下划线。

从程序的角度看,就是把一些相关的变量和函数放在一个类中。本例将鱼定义为一个类,类的名字是fish,类名与函数起名规则一样,并且也使用冒号和缩进显示出类所在的程序块。

01 class fish: 
02     color = 'blue' # 存储颜色的变量 
03     length = 5 # 存储长度的变量 
04 
05 def __init__(self,c,l): # 构造函数 
06     self.color = c 
07     self.length = l 
08          
09     def swim(self): 
10         print("swim swim swim...") 
11 
12     def show(self): 
13         print("color:", self.color, "length:", self.length) 
14 
15 f = fish('red',10) # 创建金鱼实例 
16 f.show() # 调用类中的方法

类中包括两个变量颜色color和长度length,以及两个函数游泳swim()和显示show(),以及构造函数init(),它是一个特殊的函数,在创建类时被调用

从程序中也可以看到,类中每个函数都包含参数self,self代表当前实例(比如金鱼)。在类的函数中使用类的变量时,如:第13行,需要在变量前加“self.”,以表明此处使用的是类中的变量。

程序运行步骤如下:

第15行创建了金鱼实例,并将该实例赋值给变量f,创建时传递了两个参数颜色“red”和长度“10”,调用类的构造函数init,第05-07行,构造函数给类变量color,和length赋值。
第16行程序,调用类的方法show(),该方法显示了类中的变量color和length的具体值。

课后练习:

练习三:创建一个关于动物的类,其中包括描述状态的变量:颜色、大小、叫声,以及描述行为的方法。基于动物类,创建一个猫的实例,并调用其中一个方法。

6.3 模块

6.3.1 Python模块

模块也称为“包”,意思是软件打包,它是事先编写的Python代码,在其它Python程序中通过import加载模块,并使用其中的函数和类。

Python语言提供的很多功能都放在模块中,使用前需要先加载模块,再使用其功能,比如与操作系统交互的os模块,用于数学计算的math模块等等。除了Python系统的内置模块,Python编程中还可以使用大量的第三方模块。

第三方模块是指:不是Python系统内置模块,也不是开发者自己编写,而是由其它的公司或者个人开发的模块,开发者可以下载、安装并使用这些模块的功能,以节省大量开发的时间。使用Python语言的最大优势在于具有功能丰富的三方模块支持。网络下载、图片处理、开发游戏、建立数据模型各方面功能非常丰富。三方模块需要先下载安装后才能使用。

在一开始安装软件时,Anaconda工具集除了包含Python基础环境以外,也包括了大量的科学计算、作图等常用的三方模块,减少了读者的工作量。但是读者仍需掌握安装三方模块的基本方法。本节将带领读者学习下载、安装和使用三方模块。

6.3.2 使用模块

自然语言处理是非常重要的人工智能技术,而中文又与英文不同,英文单词之间以空格分隔,而处理中文之前需要先把整句分成词,Jieba是最常用的分词工具,下面学习安装和使用分词工具。

首先,在开始菜单->所有程序->Anaconda中,打开Anaconda Prompt,使用以下命令安装jieba模块。

01 pip install jieba

pip是Python的包管理工具,用于安装、卸载、查看Python中的三方模块。Install用于安装,使用install参数加模块的名称,可将三方模块安装到Python系统中。安装成功之后,即可使用该模块中的类和函数。

01 import jieba 
02 
03 arr = jieba.lcut('我爱北京天安门') 
04 print(arr) 
05 # 运行结果:['我', '爱', '北京', '天安门']

第01行使用import命令导入了jieba分词模块。
第03行使用该模块中的lcut方法将句子“我爱北京天安门”切分成字符串列表
第04显示出该列表内容。

利用三方模块,程序员只需两三行代码即可实现分词的功能。

import 命令有几种常用方法:

  • 方法一、导入包名是最常用的方法,分词例程中就使用了这种方法。
01 import 包名 02 包名.函数名(参数...)
  • 方法二、导入包中指定的几个函数。
01 from 包名 import 函数名1,函数名2... 
02 函数名1(参数...)
  • 方法三、有时包名比较长,为了简化引用时输入的内容在导入时用简短的别名代替包名。
01 from 包名 as 别名 
02 别名.函数名1(参数...)

课后练习:

练习四:安装Python的游戏开发模块pygame(请参考安装Jieba分词模块的方法),并在程序中导入该模块(使用Jupyter Notebook或Spyder编写程序)。

练习五:出五十道一百以内的加减法口算题,并显示在屏幕上。
(本练习类似于第三讲的第五题,不同的是需要出五十道题,并且是加减法混合题,将综合利用到循环、判断、函数等方法)

6.4 思维训练

6.4.1 函数思维

练习二是一个典型的函数应用场景:不同的数据使用同一工具。小李在计算平均分时,分别写了两个函数计算了小红和小明的平均分,如图6.1所示:

图6.1 计算平均分

这段程序虽然能显示出正确的结果,却没能利用函数一次定义多处调用的优势。这可能由于她运用了写作文的方式写程序:虽然把运算放入了函数,但是整体还是链式结构。

把两个函数改成一个很容易,而核心问题是建立“复用”的思路,这也是需要多练习的部分。函数不像洗手间的纸,一个人用完了,其它人就不能再用;它更像洗手间里的烘干机,可以反复使用。

人的器官和解决问题的方法一样也是公用的,无论去上学还是买东西,都需要认路,绕过障碍物;脚不只可以走路,还可以跳高等等。如果针对每一个问题都有配套的器官和方法,变成螃蟹腿也不够用。程序也是一样,同一功能使用多次的时候,在程序里只实现一次,其它情况使用该功能时调用它,就使用函数,以节省资源。

整个过程涉及:拆分、对比、复用。

  • 把大问题拆成小问题 大问题非常复杂,一般不可能找到完全一样的方法。吃饭技能可以分成识别食物、使用各种餐具、咀嚼食物等等,吃中餐和西餐的整体方法不同,但细分之后,小模块之间有共性。比如吃什么饭使用勺子方法都差不多。
  • 提炼问题的共性和差异 把共性多的分为一类,再找到它们的差异。在编写函数时就是函数的参数,通过不同的参数让同一函数完成不同的功能。

6.4.2 结构和功能

函数分开了结构和功能,编写函数的人注重函数中的原理和具体的实现方法,即结构;而使用函数的人主要关注函数的功能和调用方法,即功能。因此,像分词、绘图、算法这些复杂的功能,只要会调函数,即使不明白原理,也能通过调用库函数正常使用。

在生活中的很多工具,比如吃药,不理解其成份原理,只要知道它的用途和用法,就能正常使用,写程序也是一样,在初学阶段会用即可。其原理可能非常复杂,需要更多的基础知识,往往花了大量时间,还没开始工作。建议在开始阶段先用现有的工具搭好框架,如有需要再进一步研究。

把难以理解的复杂过程用函数名代替,不需要考虑太多细节,从而有更多的空间用于思考更重要的问题。Python最大的优势就是有大量三方库,开发者可以利用简单的方法开发各种复杂的功能。

6.4.3 容易理解的程序

好的程序不但能正常运行,还需要让自己和别人都能看懂,程序很多时候需要给别人看。有人喜欢写得非常复杂和玄妙,写程序就像写文章一样,用篆书看着是有学问,但是写完了别人看不明白。不要给自己和他人增加认知负担。

因此,程序尽量写得大家都能看懂,需要注意:

  • 使用有意义的变量和函数命名。
  • 程序段不要写得过长,程序段太长时,可以拆分成函数。
  • 写好程序注释。

6.5 小结

6.5.1 单词

本讲需要掌握的英文单词如表6.1所示。

表6.1本讲需要掌握的英文单词

6.5.2 习题答案

1. 练习一:用百度搜索几个Python常用的数学函数及其使用方法:求和、求最大值和最小值。

在百度搜索关键字如:Python 最小值,然后参考网页中的例程。

01 print(min(1,2,3)) 
02 print(max(1,2,3)) 
03 print(sum([1,2,3]))

2. 练习二:定义一个函数,计算语文、数学、英语三门考试成绩的平均分,并调用该函数计算小明语文90、数学95、英语80,和小红语文93,数学96,英语97,两名同学各自的平均分。

01 def meani(a,b,c): 
02     return (a+b+c)/3 
03 
04 x=mean (90,95,80) 
05 y=mean (93,96,97) 
06 print(x) 
07 print(y)

3. 练习三:创建一个关于动物的类,其中包括描述状态的变量:颜色、大小、叫声,以及描述行为的方法。基于动物类,创建一个猫的实例,并调用其中一个方法。

01 class animal: 
02     color='red' 
03     length=15 
04     suoed='wang' 
05 
06 def __init__(self,c,l,s): 
07 self.color=c 
08     self.length=l 
09     self.suoed=s 
10 
11 def show(self): 
12     print("color:",self.color,"length:",self.length, "suoed:",self.suoed) 
13 
14 c=animal('black',20,'miao') 15 c.show()

4. 练习四:安装python的游戏开发模块pygame,并在程序中导入该模块。

在命令行安装模块:

01 pip install pygame

在程序中导入模块

01 import pygame

5.练习五:出五十道一百以内的加减法口算题,并显示在屏幕上。

01 import random 
02 
03 def k(): 
04     d=random.random()*100 
05     e=random.random()*50 
06     q=random.random()*50 
07     w=random.random()*50 
08     print(int(q),'+',int(w),'=') 
09 if d > e: 
10         print(int(d),'-',int(e),'=') 
11 if e > d: 
12         print(int(e),'-',int(d),'=') 
13 
14 for i in range(1,25): 
15     k() 

少儿Python编程_第五讲:程序流程控制

少儿Python编程_第五讲:程序流程控制

除了顺序执行程序以外,所有编程语言都支持判断和循环,并且语法都相似。本讲首先讲解如何画程序流程图,然后分别介绍实现判断和循环的几种方法。

5.1 程序流程图

画程序流程图主要目的是梳理思路,有很多软件都支持画流程图,比如Word中菜单:插入->形状->流程图,就可以绘制最简单的流程图。

流程图包括二十多种图形代表不同含义,但一般用到的流程图非常简单,只需要掌握几个常用的图形即可。

1.起始框/终止框

流程图用圆角矩形表示程序的开始和结束,用箭头表示数据流。

2.执行框

用矩形表示具体的操作步骤。

3.判断框

用菱形表示判断条件。

4.数据框

用平行四边形表示数据的输入输出。

5.顺序执行

最简单的程序是顺序执行的程序,程序代码从开始到结束逐行执行,一般包括:开始、结束、程序的执行步骤,有时也包括输入、输出,图5.1展示了程序运行的最基本流程。

图5.1程序基本流程图

5.2 条件语句­

判断用于解决决策问题,比如判断分数,如果60分及60分以上显示为合格,60分以下则显示不合格。程序根据不同的条件进行不同的操作。

条件语句根据关系运算或者逻辑运算的条件表达式来判断程序执行的流程,条件语句又分成以下几种情况:

1.单向条件语句 if

单向条件语句只在条件成立时,执行程序块,其流程如图5.2所示:

图5.2单向条件语句流程图

其语法是:

01 if 条件表达式: 
02     程序块

其中程序块可以是一行或者多行,为说明程序与条件语句的关系,程序块内容以每行加四个空格的方式缩进。另外需要注意的是条件表达式之后需要加冒号,条件语句也可以写在一行,形如:

01 if 条件表达式:程序块

例如:如果成绩高于60分,则显示及格,否则不显示信息

01 score = 61 
02 if score >= 60: 
03     print("及格")

2.双向条件语句 if...else

双向条件语句在条件成立时,执行程序块1,在条件不成立时,执行另一个程序块2,其流程如图5.3所示:

图5.3双向条件语句流程图

其语法是:

01 if 条件表达式: 
02     程序块1 
03 else: 
04     程序块2

例如:如果成绩高于60分,则显示及格,否则显示不及格

01 score = 59 
02 if score >= 60: 
03     print("及格") 
04 else: 
05     print("不及格")

3.多向条件语句 if...elif...else

多向条件语句的功能更强大,在一段代码中可以判断多个条件,一般更为常用。其流程如图5.4示:

图5.4多向条件语句流程图

其语法是:

01 if 条件表达式1: 
02     程序块1 
03 elif 条件表达式2: 
04     程序块2 
05 else: 
06     程序块3

上面介绍了最简单的语法,还可以使用elif加入更多条件。

4.冒号和缩进

Python用冒号和缩进(行首的空格)区分代码之间的层次,从条件语句中可以看到,满足if条件表达式时,执行的程序块都包含同样的缩进。

缩进的空格数量是可变的,但是具有同一层次的所有语句必须包含相同的缩进空格数量,另外,需要注意的是:如果使用普通的文本编辑器(比如记事本),用Tab键和空格键生成的缩进即使看起来一样,但在程序处理时也有差异;如果使用Spyder或者Jupyter编写程序,输入时工具将Tab自动转换成空格。

冒号和缩进一般配合使用,如果冒号后直接换行,那么下一语句(或者程序块)必须缩进。后面学习的for循环,while循环以及定义函数和类都会用到程序块缩进。

课后练习:(练习答案见本讲最后的小结部分)

练习一:某学生成绩为73分,请写程序显示其评级(60分以下为“不及格”,60-75分为“及格”,75-85分为“良”,85分以上为“优”)。

5.3 循环语句­

有时会遇到同一段语句需要反复执行的情况,此时可使用循环语句实现,判断当满足一定条件时反复执行某一程序块。

5.3.1 while循环

while循环是最为简单的循环语句,它判断循环条件是否成立,如果成立则执行程序块,然后再判断条件;如果条件不成立,则循环结束,执行循环之后的程序。其流程如图5.5所示:

图5.5 while循环流程图

其语法是:

01 while 条件表达式: 
02     程序块

例如下面程序用input方法接收用户输入,并显示出用户的输入的字符,直到用户输入q,则退出循环。

01 a = input() 
02 while a != 'q': 
03     print("输入:", a) 
04     a = input()

5.3.2 for循环

for循环是最为常用的一种循环,不同于while循环的是:for循环常常在一开始就确定了循环的次数和内容,其最简单的语法是:

01 for 变量 in 列表: 
02     程序块

列表list由多个元素组成,for循环按顺序访问列表中的每一个元素,将其逐个赋值给变量,然后执行循环体中的程序块。

例如:显示列表中所有元素的值。

01 a = [1,3,5] 
02 for i in a: 
03     print(i)

(注意:一定要在计算机中运行例程,做比看更重要)

程序的执行顺序如下:
01行,将3个元素的列表赋值给变量a。
02行,进入循环,第一次执行时,变量i指向列表a的第0个元素1。
03行,执行循环体中的程序块print(i),打印出变量i的值1。
02行,继续循环,第二次执行时,变量i指向列表a的第1个元素3。
03行,执行循环体中的程序块print(i),打印出变量i的值3。
02行,继续循环,第三次执行时,变量i指向列表a的第2个元素5。
03行,执行循环体中的程序块print(i),打印出变量i的值5,列表内容遍历完毕,退出循环,程序结束。

逐个访问元素的值也叫遍历,除了遍历列表,for循环还可以遍历元组、集合等结构。

for循环常和range方法配合使用,用于控制循环次数。range用于创建一个由整数构成的列表,它的语法是:

01 range(起始值, 终止值[, 步长])

其中中括号内的步长是可选项,其默认值为1,例如:

01 for i in range(1,5): 
02     print(i,end=",") 
03 # 运行结果:1,2,3,4

以上程序生成了从1到5(不包含5),步长为1的列表[1,2,3,4],并使用for遍历该列表,其中print方法的参数end指定打印信息以逗号结束(默认为换行结束),使得程序结果可以在同一行显示。

课后练习:

练习二:使用for循环遍历集合b = {5,6,7}中的所有元素。
练习三:使用for循环求从1到100所有整数之和。
(提示:使用变量存储加法结果)

5.3.3 终止循环

执行循环过程中可使用break和continue两种方法提前结束循环,break是直接跳出循环,执行循环之后的语句,而continue是结束正在执行的程序块,跳到循环开始的条件表达式继续执行。

用break终止循环。

01 for i in [1,2,3,4,5]: 
02     if i == 3: 
03         break 
04     print(i,end=",") 
05 # 运行结果:1,2,

用continue终止本次循环。

01 for i in [1,2,3,4,5]: 
02     if i == 3: 
03         continue 
04     print(i,end=",") 
05 # 运行结果:1,2,4,5

从运行结果可以看出,break终止了整个循环,而continue只跳过了本次循环程序块内的剩余内容。

开始学习编程最好的方法就是把自己当作计算机,按程序执行的顺序逐行执行程序。

对于break 示例,程序执行的顺序是:
01行:此时i值被赋予列表[1,2,3,4,5]的第0个元素1,即i=1。
02行:判断i是否等于3,结果为不等于,即假False,不执行03行,直接跳到04行。
04行:显示i值,并以逗号作为结束符,即显示“1,”。
01行:继续下一次循环,此时i被赋予列表[1,2,3,4,5]的第1个元素2,即i=2。
02行:判断i是否等于3,结果为不等于,即假False,不执行03行,直接跳到04行。
04行:显示i值,并以逗号作为结束符,即显示“2,”。
01行:继续下一次循环,此时i被赋予列表[1,2,3,4,5]的第2个元素3,即i=3。
02行:判断i是否等于3,结果为等于,即真True,执行03行。
03行:break终止循环,程序结束。

课后练习:

练习四:用上述方法逐句分析continue示例中的程序执行过程。

5.3.4 循环嵌套

条件语句和循环语句都可以嵌套使用,比如一个for循环中再套一个for循环,就称为for循环嵌套。当然,也可以根据需要在while循环中的程序块内嵌套for循环等等。

程序嵌套中需要注意的是:先执行内层循环,再执行外层循环。例如:以下程序使用了双层for循环,实现了显示由“*”堆叠三角形的功能。

01 for i in range(1,4): 
02     for j in range(0,i): 
03         print("*",end="") 
04     print() 
05 # 运行结果: 
06 * 
07 ** 
08 ***

程序执行的顺序是:
01行:此时i值被赋予列表[1,2,3]的第0个元素1,即i=1。
02行:j被赋予列表[0]的第0个元素0,即j=0。
03行:显示并且不换行(使用end=””去掉了换行符),内层循环遍历的列表只有一个元素,内层循环结束。
04行:显示换行(第六行的星号显示完成),之后继续外层循环。
01行:此时i值被赋予列表[1,2,3]的第1个元素2,即i=2。
02行:j被赋予列表[0,1]的第0个元素0,即j=0。
03行:显示并且不换行,继续内层循环。
02行:j被赋予列表[0,1]的第1个元素1,即j=1。
03行:显示并且不换行,内层循环结束。
04行:显示换行(第七行的星号显示完成),之后继续外层循环。
01行:此时i值被赋予列表[1,2,3]的第2个元素3,即i=3。
02行:j被赋予列表[0,1,2]的第0个元素0,即j=0。
03行:显示并且不换行,继续内层循环。
02行:j被赋予列表[0,1,2]的第1个元素1,即j=1。
03行:显示并且不换行,继续内层循环。
02行:j被赋予列表[0,1,2]的第2个元素2,即j=2。
03行:显示并且不换行,内层循环结束。
04行:显示换行(第八行的星号显示完成),外层循环结束。

循环嵌套对于大人来说很容易理解,但是对于低年龄儿童(9岁以下)理解起来有一定难度,小读者往往可以轻松理解单层循环,却搞不清循环嵌套的运行顺序。因此,对于三年级以下的小读者,本小节及对应练习题为选做题,不要求掌握。

课后练习:

练习五:用for循环嵌套方式显示九九乘法表。
提示:字符串可用加号连接,形如:

01 print(str(3)+"x"+str(5)+"="+str(15)) 
02 # 运行结果:3x5=15

练习六:画出你理解的循环嵌套。

5.3.5 列表推导式

列表推导式 list comprehension用于快速生成列表,其语法如下:

01 [表达式 for 变量 in 可迭代对象]

01 [表达式 for 变量 in 可迭代对象 if 真值表达式]

例如:生成20以内奇数(单数)组成的数组,用列表推导式,一行代码即可实现:

01 a = [i for i in range(20) if i % 2 == 1]

其含义是用for循环访问由range函数创建的含有数值0-19的列表,用其中不能被2整除的数i生成新列表。

5.4 思维训练

判断和循环可以说是程序领域中最重要的逻辑问题。其它大多数方法,都是描述性顺序执行的链式结构,类似写作文,只需要简单的代入即可使用。而判断和循环与自然语言有明显地不同,把这种思维代入其它日常问题之中,也是一种思维拓展。

5.4.1 拆分复杂问题

每个人的时间、精力,大脑的资源都有限,而训练思维的目标注是善用大脑资源。无论大人还是小孩都无法一次性解决非常复杂的问题。把复杂的问题分解成小问题再逐步处理是解决所有复杂问题的方法。

条件判断If...else在编程过程中提供了对问题一分为二的处理方法:如果符合条件则执行程序段一,否则执行程序段二。当遇到三种以上的可能性时,可以使用if...elif...elif...else的方法逐一处理。还可以嵌套判断,比如:在性别是“女”的条件下,继续判断高矮胖瘦,从而组合出更加复杂的逻辑,梳理事情的每一种可能性,把复杂的问题分层分步处理。

一般人脑只能同时考虑两种特征的组合,比如特征“身高”、“体重”,其可能性有:高胖、矮胖、高瘦、矮瘦四种,三种特征则有九种可能性,很难同时处理。这还是仅考虑一分为二的情况,而不是身高体重的具体值。虽然并不存在绝对一分为二的问题,比如绝对的胖瘦之分。但逻辑思维简化了问题。让人们有余力处理更复杂的事物。

使用条件判断,除了学习语法以外,还需要考虑:将什么作为判断条件,当存在多个条件时,先判断哪一个。常用的方法是选择主要特征,观察其与众不同的地方,写作文、画漫画也是同样道理。

比如写一个找人的程序,描述某个小女孩,特征是马尾辫,小圆脸,很可爱……虽然也没错,但是很多女孩都具备这几个特征,程序中这样的描述就没什么作用。但是像班里个子最高,长得最胖,眉毛很重,这种特征辨识度更强,代码也更加简单。这一方法在机器学习中叫特征重要性排序。

网上一些文章为了引人关注,往往写一些违反常识的标题,也是同样道理。

5.4.2 循环和嵌套

循环是一种环形结构,它可以重复做同一件事,每一次操作可能又有细微的差别,且操作之间有规律可循。

程序中什么情况下需要使用循环呢?首先,需要定位被反复执行的代码段;然后分析每一次执行时的差异,并且用变量来描述差异;还要确定循环的次数或者范围……因此,使用循环也是提炼和简化问题的过程——用同一种方法解决类似的多种问题,循环的思路有利于举一返三。

循环结构与前一讲学习的链式结构同属于描述过程的方法,链式结构常用于推理和归因,循环结构用于归因时可能出现是:鸡生蛋还是蛋生鸡的互为因果的问题,如果追溯回到了原点,则需要检查是否陷入死循环。

嵌套也是一个重要思路,就像俄罗斯套娃一样。比如一年有三百六十五天,一天有二十四个小时,一小时六十分钟,一层套一层。

在我的孩子二年级上半学期的时候,曾经尝试学习编程语言,就“卡”在了循环嵌套的问题上,她能指着可回收垃极的图标说“这个图就像循环一样”,但仍然不能独立解决打印乘法口诀表的问题。究其原因,可能有两方面:

  • 第一:因为前期对基础知识掌握不牢固,只是粗略地看书和听讲,没有动手实验,或者实验时照猫画虎,不理解其背后的原理。
  • 第二:低年龄儿童逻辑和理解能力有限,基因在不同的年龄阶段开启了不同技能,低年龄儿童对多层次关系的存储和使用有一定困难,学习难度较大。

积累知识如同盖楼,需要身体结构和知识结构同时支撑。强行增加难度,学习过程对于老师和学生都容易产生挫败感,严重时可能产生来自于思维内部的“智能创伤”,产生“我不擅长于此”的心理阴影,如果此时再听到一些宿命论的声音:“聪不聪明都是天生的”。不但没能“抢跑”,反而起到了负面作用。

5.4.3 微调和重构

本讲的练习中需要使用:常量,变量,表达式,运算符,判断,循环,以及多重循环,可以说开始了正式编写程序。

之前几讲的练习几乎都是框架不变,只需要替换具体数值,即可实现功能。而本次练习需要将所有元素打散再重组,如同造句和写作文的区别。

程序一般包含“输入->处理->输出”的过程。人也一样,学习记忆就是输入,常常这样要求小朋友:要好好做作业,背书,按时打卡……这样会不会培养出一个当一天和尚撞一天钟的小朋友?看起来很认真的样子,其实内部知识组织非常散乱模糊?认真还不行,是不是就只能归咎于智力问题?

积累到一定的程度,就需要把知识梳理、归类、组织起来,而这些内部过程却很难量化,如果不能监督过程,就只能用结果评价,通过输出的效果来衡量会不会重构、活用、真正地解决问题,这时候那些薄弱环节也更容易暴露出来。

一开始可能会进步很慢,其实内部正在“构建”的过程之中,此时,思维导图也可以起到辅助作用。

5.5 小结

5.5.1 单词

本讲需要掌握的英文单词如表5.1所示。

表5.1本讲需要掌握的英文单词

5.5.2 习题答案

1练习一:某学习成绩为73分,请写程序计算其评级(60分以下为“不及格”,60-75分为“及格”,75-85分为“良”,85分以上为“优”)。

01 score=73 
02 if score>=85: 
03     print("优") 
04 elif score>=75: 
05     print("良") 
06 elif score>=60: 
07     print("及格") 
08 else: 
09     print("不及格")

做本练习时需要注意:分数的判断顺序,以上逻辑为先判断高分再判断低分,也可以使用逻辑运算:如(score>=75 and score<80)来锁定范围;另外,也要注意大于和大于等于的区别。

2练习二:使用for循环遍历集合b = {5,6,7}中的所有元素。

01 for b in {5,6,7}: 
02     print(b,end=",")

做本练习时需要注意遍历的是集合,而非列表。

3练习三:使用for循环求从1到100所有整数之和。

01 o=0 
02 for i in range(1,101): 
03     o=o+i 
04 print(o)

做本练习时需要注意定义变量o用于存储结果,也让读者进一步理解变量的存储作用。

4练习四:逐句分析continue示例中的程序执行过程。

01 for i in [1,2,3,4,5]: 
02     if i == 3: 
03         continue 
04     print(i,end=",") 
05 # 运行结果:1,2,4,5

01行:此时i值被赋予列表[1,2,3,4,5]的第0个元素1,即i=1。
02行:判断i是否等于3,结果为不等于,即假False,不执行03行,直接跳到04行。
04行:显示i值,并以逗号作为结果符,即显示“1,”。
01行:继续下一次循环,此时i被赋予列表[1,2,3,4,5]的第1个元素2,即i=2。
02行:判断i是否等于3,结果为不等于,即假False,不执行03行,直接跳到04行。
04行:显示i值,并以逗号作为结束符,即显示“2,”。
01行:继续下一次循环,此时i被赋予列表[1,2,3,4,5]的第2个元素3,即i=3。
02行:判断i是否等于3,结果为等于,即真True,执行03行。
03行:continue终止本次循环,跳到第01行继续下一次循环。
01行:继续下一次循环,此时i被赋予列表[1,2,3,4,5]的第3个元素4,即i=4。
02行:判断i是否等于3,结果为不等于,即假False,不执行03行,直接跳到04行。
04行:显示i值,并以逗号作为结束符,即显示“4,”。
01行:继续下一次循环,此时i被赋予列表[1,2,3,4,5]的第4个元素5,即i=4。
02行:判断i是否等于3,结果为不等于,即假False,不执行03行,直接跳到04行。
04行:显示i值,并以逗号作为结果符,即显示“5,”,之后程序结束。

5练习五:用for循环嵌套方式显示九九乘法表。

01 for i in range(1,10):
02     for j in range(1,10):
03         if j<i or j==i:
04             print(j,"*",i, "=", i*j,end=" ")
05     print()

6练习六:画出你理解的循环嵌套。

下图为小李同学作业:

图5.6循环嵌套示意图



少儿Python编程_第四讲:Python数据类型

少儿Python编程_第四讲:Python数据类型

上一讲学习了大多数编程语言都支持的基本数据类型,本讲将介绍Python语言特有的数据类型,这些数据类型以基本数据类型为基础,使用起来非常方便。比如:大多数编程语言都需要定义数据结构,而使用Python的字典类型就可以实现结构的功能。

4.1 列表

列表list是Python最常用的数据类型,它是一组元素序列。列表使用方括号定义,元素之间用逗号分隔。它常用于描述多个同类型的数据,比如一个班级内每个同学的语文成绩。

列表形如:[1,2,3,4],其中的1,2,3,4是列表中的元素,也叫数据项,有时也被称为下标

列表支持异构,即:其中各个数据项类型可以不同,其中的数据项可以是任何类型。下面将从新建、增加、删除、访问、修改,几个方面介绍列表的基本操作。

1. 创建列表

首先,用赋值表达式创建两个列表a和b,a列表中有4个元素,b列表中有3个元素。

  01 a=[1,2,3,4] 02 b=[5,6,7]

2. 访问元素

列表中的内容是有序的,元素在列表中的位置用索引号表示,索引号从0开始计数,比如列表x=['a','b','c','d']中一共有四个元素,其中的索引号为0的元素x[0]是'a',索引号为1的元素是'b',索引号为2的元素是'c',索引号为3的元素是'd'。

通过索引号可以访问数组中的元素。

01 x=['a','b','c','d'] 
02 print(x[0]) 
03 运行结果:'a'

列表支持双向索引,即正数为从左向右索引,负数为从右向左索引(-1为最后一个元素)。

01 print(x[-1]) 
02 # 运行结果'd'

列表支持切片操作,切片是Python中特有的操作,list 的索引部分可以接收三个参数,分别是起始下标、结束下标和步长,用冒号分隔,例如:

01 print(x[0:3:2]) 
02 # 运行结果:['a', 'c'] 
03 print(x[2:3]) 
04 # 运行结果:['c']

从运行结果可以看到,切片的结果是列表,而不是具体的元素。

例程01行,设定了开始下标为第0个元素,结束下标为第三个元素,步长为2,输出为第0个元素’a’,第2个元素’c’。
例程03行,设定了开始下标为第0个元素,结束下标为第三个元素,此处省略了步长,步长默认为1,输出第2个元素’c’,但不包含第3个元素,也就是说,切片包括开始元素,但不包括结束元素。

用len()函数可查看列表元素个数:

01 print(len(x))

3. 增加元素

列表内容在建立后允许被修改,使用append方法可以在列表的最后增加元素:

01 a=[1,2,3,4] 
02 b=[5,6,7] 
03 a.append(100) # 追加元素 100 
04 print(a)   
05 # 返回结果: [1, 2, 3, 4, 100]

使用insert方法可以在列表的指定位置插入元素,插入时需要指定两个参数:第一个参数是插入的位置,第二个参数是要插入的数据。

01 a.insert(0, -1) # 在第0个位置插入元素 -1 
02 print(a) # 返回结果: [-1,1, 2, 3, 4,100]

使用extend方法可连接两个列表

01 a.extend(b) # 连接两个列表 
02 print(a) # 返回结果: [-1,1, 2, 3, 4,100, 5, 6, 7]

4. 删除元素

使用remove方法删除指定元素。

01 b=[5,6,7] 
02 b.remove(5) # 删除数据 5 
03 print(b) # 返回结果: [6, 7]

使用pop方法删除列表中最后一个数据。

01 b.pop() # 删除最后一个数据 
02 print(b) # 返回结果: [6]

使用clear方法清空数组中所有元素。

01 b.clear() # 清空所有数据 
02 print(b) # 返回结果: [ ]

5. 修改列表

可通过下标修改列表的内容。

01 a[0] = 9 # 修改第0个元素内容

课后练习:(练习答案见本讲最后的小结部分)

练习一:一个小组内所有同学的英语成绩是:88、89、90、85、100、77。
(1) 定义一个列表存储组中同学的英语成绩。
(2) 查看列表元素个数。
(3) 显示最后一位同学的英语成绩。
(4) 用切片方法显示前三位同学的英语成绩。
(5) 从组中删除100分的成绩。
(6) 将最后一位同学的成绩从77分改为88分。

4.2 元组

元组tuple的使用方法类似于列表,也用于表示有序的多个数据,与列表不同的是它不支持修改,它的操作速度比列表快,常用于定义不变的数据,也作为字典的键值使用。元组使用圆括号定义,元素之间用逗号分隔。

元组形如:x=(1,2,3)。由于元组不支持增删和修改改,下例介绍其创建和查询的基本方法。

1. 创建元组

首先,用赋值表达式创建元组a。

01 a = (1,2,3,4)

2. 访问元素

使用切片的方法,获取元组中从索引号1到2(不包括2),步长为1(默认值)的元素。

01 print(a[1:2]) 
02 # 返回结果 (2,)

4.3 集合

集合set用于表示一组不重复的元素,支持异构,集合使用大括号定义,元素之间用逗号分隔。

集合形如:x={1,2,3}。集合中的元素是无序的,可修改。因为无序,所以不支持通过索引号访问。

下例从增删查改几方面介绍集合的基本操作。

1. 创建集合

首先,用赋值表达式创建集合a。

01 a = {1,2,3} 02 print(a)  03 # 返回结果: {1, 2, 3}

2. 添加元素

使用add方法向集合中添加元素

01 a.add(4) 02 print(a) # 返回结果: {1, 2, 3, 4}

3. 删除元素

集合也支持remove,pop,clear删除元素,使用方法与列表一样。

01 b={5,6,7} 
02 b.remove(5) # 删除数据 5 
03 print(b) # 返回结果: {6, 7}

使用pop方法删除列表中最后一个数据。

01 b.pop() # 删除一个数据 
02 print(b) # 返回结果: {7}

使用clear方法清空数组中所有元素。

01 b.clear() # 清空所有数据 
02 print(b) # 返回结果: { }

4. 遍历集合

遍历集合是指访问集合中的每个元素,由于集合中的元素没有顺序,不能通过索引号访问,但可以使用for循环依次访问其中的所有元素,列表、元组、集合、字典等数据都可以通过for的方式遍历,for的语法,将在后面的课程中详细讲解。

01 b = {5,6,7} 
02 for i in b: print(i) 
03 # 返回结果: 04 # 5 05 # 6 06 # 7

5. 更新操作

更新操作使用update方法实现,更新的原则是:如集合中不存在该元素则添加,如果存在则忽略该元素。

01 a={1,2,3} 
02 b={3,4,5} 
03 a.update(b) 
04 print(a) 
05 # 返回结果: {1, 2, 3, 4, 5 }

6. 集合运算

除了增删查改,集合还支持一些特有运算:如差集(-)、并集(|)、交集(&)、子集(issubset)等操作。

使用'-'求差集,即:求a中有而b中没有的元素。

01 a = {1,2,3} 
02 b = {3,4,5} 
03 print(a-b) 
04 # 返回结果: {1,2}

使用'&'求交集,即:求a和b都有的元素。

01 print(a&b) 
02 # 返回结果: {3}

使用'|'求并集,即:求a中有或者b中有的元素。

01 print(a|b) 
02 # 返回结果: {1, 2, 3, 4, 5}

使用issubset方法判断一个集合中是否包括单一个集合(即子集)。

01 print(a.issubset(a)) 
02 # 返回结果: True

课后练习:

练习二:超市中的水果种类有:苹果、西瓜、樱桃、香蕉。
(1) 用集合描述水果种类。
(2) 从集合中删除香蕉。

4.4 字典

字典dict是一组键值对的集合,键值对是键key和值value的组合,集合中的键值不能重复。字典也使用大括号定义,key与value间用冒号分隔,键值对之间用逗号分隔。

字典形如:{name:'张三', age:9},其中的age为键key,即描述元素的名字,9则是元素的具体值value。字典中元素无序,其内容可修改,字典要求key为不可变的数据。

下面从增删查改几方面介绍字典的基本操作。

1. 创建字典

使用大括号包含键值对的方式创建字典。

01 a = {'a':"one", 2:"two"} 
02 print(a) 
03 # 返回结果: {2: 'two', 'a': 'one'}

2. 添加元素

使用赋值的方法向字典中添加新的元素。

01 a[3] = 'three' 
02 print(a) 
03 # 返回结果: {2: 'two', 3: 'three', 'a': 'one'}

3. 删除元素

使用pop方法,删除指定键值对应的元素。

01 a.pop(2) 
02 print(a) 
03 # 返回结果: {3: 'three', 'a': 'one'}

4. 访问字典

使用中括号指定键值,访问字典中对应的元素。

01 print(a['a']) 
02 # 返回结果: one

使用keys方法列出字典中的所有键。

01 print(a.keys())
02 # 返回结果: dict_keys([3, 'a'])

使用values方法列出字典中的所有值。

01 print(a.values()) 
02 # 返回结果: dict_values(['three', 'one'])

使用items方法列出字典中所有的键值对。

01 print(a.items()) 
02 # 返回结果: dict_items([(3, 'three'), ('a', 'one')])

5. 修改字典中元素的值

通过指定键的方法,用赋值语句修改字典中对应的值,如果该键存在,则修改其值,如果该键不存在,则将键值对添加到字典中。

01 a[3] = '3' 
02 print(a) 
03 # 返回结果: {3: '3', 'a': 'one'}

课后练习:

练习三:一位学生的基本情况是:年龄9岁、性别女、体重34公斤、身高149、爱好跳舞。
(1) 用字典描述该学生的基本情况。
(2) 显示该学生的爱好。
(3) 将该学生的爱好改为看书。
(4) 显示字典中所有数据的值。

4.5 类型转换

有时需要在各种数据类型之间转换,只要将数据类型作为函数名即可,例如:使用set方法将列表转换成集合:

01 a=[1,1,2,3] 
02 b=set(a) 
03 print(b) 
04 # 返回结果:{1, 2, 3}

从返回结果可以看到,重复的元素1被去掉,列表被转换成集合。其它类型转换方法如下:

01 c=tuple(a) 
02 print(c) 
03 # 返回结果:(1, 1, 2, 3),转换成元组 
04 d=list(b) 
05 print(d) 
06 # 返回结果:[1, 2, 3] ,转换成列表

课后练习:

练习四:请根据Python数据类型填写下表:

表4.1 Python数据类型

4.6 思维训练

4.6.1 思维链条

List是所有编程都用到的数据结构,有的编程语言自带List支持,比如Python;有的需要开发者自己编写,比如C语言;有的有三方库支持。本讲中的几种数据类型都可以看作是列表的扩展和变形,字符串也是一种特殊的列表,其中每个元素都是字母,并按顺序排列。那么什么情况下使用列表结构组织数据呢?

链式思维非常重要,被应用于各个领域,一方面,它把具有同样属性的元素组织起来,比如会把[”张三”, ”李四”, ”王五”]放在一个列表中,但不会把[”张三”, ”人类”, ”李四”]放在一个列表中,尽管这样并不影响程序正常运行,但是类别和层次的划分在写程序前在脑中已经形成;另一方面,链条也描述了元素之间的前后和变化关系,比如图4.1所示的时间序列数据,按时间先后把元素组织起来,开发者可以通过总结历史数据之间的关系,来预测未来。

图4.1 气温变化时间序列

Python语言不同于其它语言的一个特点是它支持批量操作:比如对列表中的每个元素进行同样的操作,以及对表格中的某一列进行同样的处理。

写文章或者思考问题也同样如此,比如我们在讨论普通孩子的教育时,突然用天才举例,虽然属性都是人,但操作方法不通用,相互之间也无需借鉴和比较。

4.6.2 常识和逻辑推理

除了用链条存储数据以外,思维中还常用链条的结构存储步骤,比如文档中常按1,2,3的顺序组织内容;以及按照逻辑推理的前后顺序,形成因果关系的链条。

逻辑推理,比如有A->B,并且B->C,因此有A->B->C,A->C。在过程较多的情况下,逻辑推理形成了一条细长的链条,链条中的任何一个环节出错,都后导致整条推理链失效。在数学领域中,大概正确和完全错误没有差别,逻辑推理让人们更容易发现错误。在学校解题时,问题都有正确答案,逻辑推理也很重要。

逻辑只有绝对的对错,发挥作用的范围有限,常常出现在书本上,条件确定时才能使用,但实际生活中有太多不确定。与“只要...就”“只有...才”不同,真实世界里,往往每一步都需要论证是否符合常识。与细长的逻辑链条相比,从生活中学到的,各个方面观察的知识,则连结成网,更加牢固,通向结果的路径也不只一条。

因此,一方面要训练分类、抽象、以及逻辑推理,抓住事情的主线,以便应用到更多领域;同时,也需要建立强大的常识系统,并在解决问题的过程中不断用常识论证。

4.7 小结

4.7.1 单词

本讲需要掌握的英文单词如表4.2所示。

表4.2本讲需要掌握的英文单词

4.7.2 习题答案

  1. 练习一:一个小组内所有同学的英语成绩是:88、89、90、85、100、77。

(1) 定义一个列表存储组中同学的英语成绩。

01 x=[88,89,90,85,100,77]

(2) 查看列表元素个数。

01 print(len(x))

(3) 显示最后一位同学的英语成绩。

01 print(x[-1])

(4) 用切片方法显示前三位同学的英语成绩。

01 print(x[0:3])

(5) 从组中删除100分的成绩。

01 x.remove(100) 
02 print(x)

(6) 将最后一位同学的成绩从77分改为88分。

01 x[4]=87 
02 print(x)

2. 练习二:超市中的水果种类有:苹果、西瓜、樱桃、香蕉。

(1) 用集合描述水果种类。

01 y={'苹果','西瓜','樱桃','香蕉'}

(2) 从集合中删除香蕉。

02 y.remove('香蕉')

3. 练习三:一位学生的基本情况:年龄9岁、性别女、体重34公斤、身高149、爱好跳舞。

(1) 用字典描述该学生的基本情况。

01 a={'性别': '女','年龄':9,'体重': '34kg','身高': '149cm','爱好': '跳舞'}

(2) 显示该学生的爱好。

01 print(a['爱好'])

(3) 将该学生的爱好改为看书。

01 a['爱好']='看书' 
02 print(a)

(4) 显示字典中的所有数据的值。

01 print(a.values())

4. 练习四:请根据Python数据类型填写下表:

图4.3 Python数据类型



少儿Python编程_第三讲:常量变量和数据类型

少儿Python编程_第三讲:常量变量和数据类型

无论使用哪一种编程语言,甚至是学习数学、物理,都需要掌握常量、变量、表达式的概念和用法。本讲将带领读者进入编程世界,学习程序的基本元素。

3.1 基本数据类型

基本数据类型有数值型、布尔型和字符型。它们是所有编程语言都会用到的最基本概念,是编写程序的基础。

1. 数值型

数值型是最常用的数据类型,它描述的是具体数值的大小,Python的数值型数据又分为整型和浮点型。

  • 整型用于描述整数(不包含小数点)。
  • 浮点型用于描述包含小数点的数。

例如:-3是整型,3.1则是浮点型。

2. 字符型

字符型用于描述一系列的字符的组合(文字),比如:人名,一段文章,需要显示的信息等等, 字符型数据也常被称为字符串。Python的字符型数据用“单引号”或者“双引号”引起来,例如:“1234”, ‘这是一张表格’。

3. 布尔型

布尔型用于描述真或假的概念,比如:“2是否大于3?”的结果为False。Python的布尔类型数据只有两个值:True表示真,False表示假(注意首字母为大写,其余字母小写)。

4. 空值

当不确定某个值是什么的情况下,用空值表示。比如:不知道性别是男是女的情况下,可以先将其性别设置成空值。Python中的空值用None表示。

3.2 常量和变量

常量和变量是数学中的概念,常量用于描述不变的事物,而变量用于描述可能变化的事物。比如:3是常量,因为它只能表示数值3,不能表示其它数据;而x是变量,它可能代表1,2或者其它数据。它和小学四年级开始学习的未知数x类似,用来表示还不知道的数字。

3.2.1 变量

1. 变量赋值

给变量设定值,也叫“赋值”,写法是:

01 变量名称=变量值

例如:设置变量a的值为常量2。

01 a=2

设置变量b的值为变量a。

01 b=a

被赋值的是变量,写在等号左侧;而具体的值写在等号右侧,可以是常量、变量或者表达式。

2. 变量命名规则

计算机中文件夹、文件、变量的命名都遵循各自的规则,这些规则又有一定的相似之处,它们通常都由字母数字下划线等元素组成,养成好的命名习惯非常重要,一方面可以减少错误,另一方面使程序更加容易理解,Python中变量的命名规则如下:

  • 变量名称只能由英文字母(大写或小写)、数字、下划线(_)或中文字符组成。 虽然Python 3及以上版本支持变量名中包含中文字符,但尽量少使用中文命名变量。
  • 变量名称的首字母吸只能是字母、下划线(_)或中文字符组成。 变量名称的首字母不能以数字开头。
  • 英文大小写字母被视为不同变量名。 比如:A1和a1是不同的变量。
  • 变量名不能与Python的保留字相同。 保留字指在编程语言中定义过的字,比如:用于判断的if,用于循环的for,break等等,后面会逐一讲到。不要使用已经存在的关键字。

3.使用变量

什么情况下需要使用变量呢?如果需要在程序之中存储数据,并且内容可能改变,就需要使用变量,这些数据可能只在过程中起作用,不需要显示出来。

整个内存就像一个储物柜,柜子里有大小不同的很多抽届,程序需要存储数据时,根据需要申请不同的抽屉。如果只存储一个整型数值就申请较小的空间,如果存储大段文字的字符串,就申请较大的空间;为了方便地找到存储的数据,还需要给抽屉贴了一标签,它就是变量名

一般的编程语言都需要先定义变量和赋初值后才能使用,例如C语言和Java语言中的:“int a=5;”,使用关键字int指定了变量的类型为整型,并将变量的初值设置为5。Python简化了这一过程,直接书写成“a=5”,根据数值5自动识别出变量的类型为整型。不同的编程语言写法不同,但在使用之前都需要定义变量和赋值,否则程序运行时会报错“找不到这个变量”。

综上,使用变量前,需要先在内存的柜子中找到一个合适的抽屉(类型),贴上标签(变量名),并且把东西放进去(赋初值)。之后就可以使用它存储和取出内容了。

课后练习:(练习答案见本讲最后的小结部分)

练习一:请读者画出包含常量、变量、基本数据类型的思维导图。
练习二:请读者通过百度搜索:Python语言包含哪些保留字。

3.3 数据类型转换

常量具有固定的数据类型,而变量的数据则根据赋值的情况而定。Python在给变量赋值时,不需要指定变量类型。而大多数编程语言都需要指定变量类型。

1. 查看数据类型

编写以下程序给变量a赋值后,变量a的类型为数值型。

01 a=2

编写以下程序给变量a赋值后,变量a的类型为字符型。

01 a=’2’

同样是2,但含义不同,一个是数字2,一个是字符2。使用type函数可查看变量类型。

01 print(type(a), a) 02 # 运行结果:<class 'str'> 2

从运行结果可以看到,变量a的类型为字符串str。程序中print用于在屏幕上显示信息,而显示的内容是a的类型和a的实际值,print可显示多种信息,信息之间用逗号分割。

注意:Python程序将“#”之后的内容当作是说明文字,也就是“注释”,而不作为程序执行,因此可以将说明和无需执行的程序之前加入“#”号。**

2.转换数据类型

不同的数据类型也可以相互转换,即强制转换数据类型,常用的转换命令如表3.1所示:

表3.1数据类型转换

课后练习:

练习三:请读者打开Python开发环境Jupyter notebook,新建一个程序,并定义数据型和字符类型的变量’88’,使用上述方式转换其类型,并显示其转换结果。

3.4 运算符和表达式

3.4.1 表达式

表达式,是由数字、运算符、括号、变量等元素,以有意义排列方法所得的组合,表达式通常用于计算,类似于数学中的“算式”。表达式又可分为算术表达式、逻辑表达式等等。

3.4.2 运算符

先举个简单的例子,比如:a=1+2,它的含义是将1+2的结果2赋值给变量a,其中1和2为操作数,“+”是算术运算符,“=”是赋值运算符。

  • 运算符:运算符是用于运算的符号。
  • 操作数:操作数是参与运算的数据,可以是常量,也可以是变量。
  • 赋值:赋值是指把某一个数赋给某一个变量的过程。

1. 算术运算符

运算符最简单直观的例子是“加减乘除”,即算术运算符,常用的算术运算符如表3.2所示:

表3.2算术运算符

2. 复合赋值运算符

复合赋值运算符将算术运算和赋值运算符写在一起,主要用于简化代码,例如:x = x + 3可写成x+=3,常用的复合赋值运算符如表3.3所示:

表3.3算术运算符

以下程序用于对变量x增加1,数值0加数值1结果为数值1。

01 x = 0 
02 x += 1 
03 print(x) 04 # 运行结果:1

3. 关系运算符

关系运算符用于比较两操作数之间的关系,其结果为布尔型(真True或者假False),常用的关系运算符如表3.4所示:

表3.4关系运算符

表3.3算术运算符以下程序显示出关系运算的结果,先将变量x赋值为3,然后显示关系表达式的结果,由于3>88的结果为假,因此运行结果显示False。

01 x = 3 
02 print(x>88) 
03 # 程序运行结果:False

4. 逻辑运算符

逻辑运算符用于操作数是布尔类型(真或假)的运算,其结果也是布尔类型,常用的逻辑运算符如表3.5所示:

表3.5逻辑运算符

例如:小李语文考了93分,数学考了96分,妈妈说如果两门都考95分以上,可以得到奖励,姥姥说只要有一门考过95分就可以得到奖励。以下程序使用and和or运算符,可以看到小李没有达到妈妈的标准,但达到了姥姥的奖励标准。

01   chinese = 93
02   math = 96
03   print(chinese > 95 and math > 95) # 妈妈的标准
04   print(chinese > 95 or math > 95) # 姥姥的标准
05   # 运行结果: False True

5. 运算符优先级

多种运算符常常出现在同一复杂的表达式之中,一般情况下,括号的优先级最高,然后依次是算术运算符、关系运算符、逻辑运算符。其优先级由高到低排列如图3.6所示,同级运算符按从左到或方式计算。为方便记忆,此处只列出了最常使用的运算符。

课后作业:

作业四:表达式not b>95+25,请按优先级从高到低排列表达试中运算符not、>、+、的优先级。
作业五:出五道一百以内的加法口算题,并显示在屏幕上。
提示:使用函数random生成0-1之间的随机小数,形如:

01 import random 
02 print(random.random())

3.5 思维训练

3.5.1 语言和思维

有一部分思维和感受可以用语言表达,而另一部分则无法表达,比如触觉、味觉,复杂的情感常常无法用确切的词汇描述。这一部分自己无法表达,对于别人的这部分思维,我们也只能猜测。就像绘画、音乐常常给人带来不可言喻的感受,不同观众感受也不同。这也正是人的不同个性所在。

人们对可以用语言表达的思维,往往有更多共识,比如说到猫、香蕉,树、房子的时候,不同人的脑中呈现的事物往往是类似的。语言不仅能表达思维,也常常是引导思维。比如读到一篇生动的文章时,虽然没亲眼看到文中的场景,但是山森、小河的景象也会出现在头脑之中。

在说话、写文章、甚至写程序时,语言也呈现出思维的条理,在面试程序员时,常常请面试者写一段代码,从代码中可以看到程序员的思路是否清晰。相对的,也可以通过练习叙述、写作、写程序来锻炼思维。

比如写变量名,理论上只要语法正常,程序就能正常运行。但一般情况下需要从名字里能推导出意思,好的程序就像文章一样,自己和别人都能轻松地看懂。很多初学者喜欢用简称起变量名,简到一段时间之后自己都读不懂;也有人起名非常复杂啰嗦。起名虽然不影响功能,但也很重要,其核心是表达意思,如果小读者不熟悉英文,也可以使用拼音。

3.5.2 抽象和泛化

从常量到变量也是抽象问题的过程,比如:1+2=2+1,用变量表示为a+b=b+a,将1、2两数做加法的交换扩展成为任意两数做加法位置可交换——把具体的、个别的经验总结出来称为抽象,再推广到其它的问题和领域,称为泛化。

程序中运行过程中,多次使用相同的方法,只需要修改其中一小部分时,常使用变量。比如只修改圆心点和半径长度,就可以用同一绘图方法,在不同的位置画出大小不同的圆形。从定义变量、编写函数、到后面将要学习的定义类、构建函数库,都是对问题的抽象。因此学习编程的过程也是锻炼抽象问题和泛化的过程。

在泛化过程中需要注意,如何定义泛化对象,也就是如何定义变量x。对于复杂的数学应用题来说,不能正确定义变量,则无法解题;其它问题也是一样要找到关键点,比如狗被汽车撞了之后,就不再去被撞那条街了,但它仍然追着汽车跑……怕就是一个错误的泛化。

另外,需要注意的问题是抽象的层次,每一个层次对应不同的特性。如图3.1所示,可以定义成一个生物,一只动物,一只猫,一只白猫,或者一只小白母猫。

图 3.1 从抽象到具体

理论上看,在哪个层次抽象都没错,但多数情况下它被看作“一只猫”。因为“生物”太过概括,对现实没什么指导意义;而“小白母猫”又太过具体,细节太多,起作用的范围也太小。另外,抽象的层次也与最终的目标有关。可以通过多画思维导图来锻炼抽象能力。

3.6 小结

从本讲开始学习编写程序,请Python初学者把每一行程序输入计算机运行,理解每一条语句,完成每一道习题。不但要理解,简单的语言还要会默写。否则,遇到后面的复杂程序时,还需要回来补课。

3.6.1单词

本讲需要掌握的单词如表3.7所示:

图3.7 需要掌握的英文单词

3.6.2 习题答案

1.练习一:请读者画出包含常量、变量、基本数据类型的思维导图。

图3.2 数据的思维导图

2.练习二:请读者通过百度搜索:Python语言包含哪些保留字。

打开浏览器,并搜索“python 保留字”,小读者如果不会中文打字,输入拼音也可以,需要注意的是关键词之间需要以空格分隔。点开返回的搜索内容即可看到python的保留字,从中了解保留字如:False,True,None,as, assert, break, class, continue, def……

图3.3 搜索保留字

3.练习三:请读者打开Python开发环境Jupyter notebook,新建一个程序,并定义数据型和字符类型的变量’88’,使用上述方式转换其类型,并显示其转换结果。

01 x=88 02 a=str(x) 03 print(type(a))

4.作业四:表达式not b>95+25,请按优先级从高到低排列表达试中运算符not、>、+、的优先级。

优先级从高到低依次是:*、+、>、not

5.作业五:出五道一百以内的加法口算题,并显示在屏幕上。

本题涉及了常量、变量、类型转换等知识点,以下程序为小李同学完成的本课作业,写法比较简单,后面课程将学习使用循环判断等方法扩展功能和简化代码。

01   import random
02   q=random.random()*50 # 乘50使加法结果不超过100
03   w=random.random()*50
04   e=random.random()*50
05   r=random.random()*50
06   t=random.random()*50
07   y=random.random()*50
08   u=random.random()*50
09   i=random.random()*50
10   o=random.random()*50
11   p=random.random()*50
12   a=int(q) # 将float型转换成int型
13   s=int(w)
14   d=int(e)
15   f=int(r)
16   g=int(t)
17   h=int(y)
18   j=int(u)
19   k=int(i)
20   l=int(o)
21   z=int(p)
22   print(a,'+',s,'=') # 用print显示常量和变量,用逗号分隔
23   print(d,'+',f,'=')
24   print(g,'+',h,'=')
25   print(k,'+',j,'=')
26   print(l,'+',z,'=') 

少儿Python编程_第二讲:开发环境

少儿Python编程_第二讲:开发环境

在开始编写程序之前,首先要搭建开发环境。Python是一种跨平台的编程语言,它可以在Window、Linux、MacOS等操作系统上运行,为简化操作,本书以Windows系统作为开发平台,以Anaconda套件作为开发工具。

2.1 Python语言

在讨论如何选择编程语言之前,先看看什么是编程。现在很多工作都离不开计算机,比如:使用各种办公软件,做图,编辑视频,开发网站,微信和手机应用,统计分析,机器人,人工智能……应该学习什么?对于非专业人员,针对青少年的知识和能力,能学什么?

希望本次学习的成果能在后续的学习和工作中发挥作用,那么就需要学习“编写真正的程序”,而不仅仅是展示某种“有趣的成果”。

图书馆里有很多十几年前的计算机工具书籍都已经不再使用,IT行业日新月异,即使今天学习了一门最流行的编程语言,等十几年后,可能也已经过时了。

因此,最好能学习一门相对简单的编程语言,不要把时间都花在语言的细节和技巧上,Python语言就非常合适,它可烦可简。Python入门简单,从8岁到80岁都可以学习;同时功能强大,在人工智能领域,它几乎是使用率最高的编程语言。小学生和博士生都在使用。利用这门简单的语言,编程者可以把更多的精力放在目标和流程上,像搭建积木一样,Python语言和它强大的三方库负责解决具体问题。

2.2 安装软件

无论是否编写程序,安装软件都是使用计算机的必备技能之一。本节将通过安装Python开发环境,向读者介绍从网上下载、安装和使用软件的步骤和方法。

2.2.1 Anaconda开发环境

Python可在多个操作系统中运行,也有多种安装方法,本书将Windows系统作为基础系统,使用Anaconda套件作为开发环境,Anaconda是一个免费开源的Python发行版本,支持多个操作系统,除了基本的Python环境,它还包括科学、工程、绘图等多种Python三方库,以及Spyder和Jupyter等Python编辑器。非常适合初学者使用,省去了后续装库的麻烦。

一般下载软件的方法是:用浏览器打开“百度”搜索软件相关的关键字,如图2.1所示:

图2.1 搜索待安装软件

图2.1中搜索出的第一项即Anacoda的主页,点击它进入下载界面:anaconda.com/distributi,如图2.2所示:

图2.2 Anaconda下载界面

可以看到下载页提供了Windows、macOS、Linux三个平台对应的软件,这里选择Windows平台的Python 3.7版本,其中包括32位和64位两种软件版本,需要根据自己计算机的情况下载不同版本,在计算机的桌面上右键点击“计算机”,选“属性”,即可从系统类型中查看计算机是32位系统还是64位系统。在浏览器中点击对应版本,下载完成后即可安装。

注意:Anaconda是英文软件,在下载和安装的过程中,低年龄儿童可能遇到大量生词,建议家长先帮助孩子下载“金山词霸”或其它翻译软件,以克服语言障碍,或者在家长的帮助下完成第一次软件安装。

2.2.2 安装软件

下载Anaconda后安装步骤如图2.3所示,按提示点击下一步(Next),同意(I Agree),安装(Install),完成(Finish)即可。

图2.3 安装Anaconda

安装完成之后,在开始菜单->所有程序->Anaconda3文件夹下可以看到Python相关的应用程序,如图2.4所示:

图2.4 Python相关应用程序

其中Anaconda Navigator是导航工具,使用它可以操作Anaconda安装的软件;Anaconda Powershell Prompt和Anaconda Prompt是命令行模式,可以在此处管理和安装Python软件;Spyder和Jupyter Notebook是程序编辑器,后续将使用它们编写Python程序,后续章节将具体介绍。

2.2.3 卸载软件

与安装软件对应的是从系统中删除软件,即卸载软件。具体方法是:点击桌面上的“计算机”图标,选择其窗口上方的“打开控制面板”->程序->卸载程序,即可打开“程序和功能界面”,如图2.5所示,从列表中选择要更改或者卸载的应用程序。

图2.5 程序和功能界面

课后练习:(练习答案见本讲最后的小结部分)

练习一:安装软件Firefox浏览器。

2.3 使用Python开发环境

可用于Python开发的环境非常多,本节将讲解其中最常用的几种环境。

2.3.1 Python命令行

首先,打开命令行界面:开始菜单->所有程序->Anaconda->Anaconda Prompt。并输入“python”,进入Python命令行模式,如图2.6所示。

图2.6 Python命令行界面

看到提示符“>>>”,可输入python命令

 01 print("aaaa")

print用于显示输出,回车后该程序被运行,显示“aaaa”,之后使用exit()退出Python命令行模式。

2.3.2 IPython命令行

IPython命令行是Python命令行的加强版,它的使用方法是先打开命令行界面:开始菜单->所有程序->Anaconda->Anaconda Prompt。然后输入ipython进入交互命令行模式。如图2.7所示。

图2.7 IPython界面

可以看到,IPython的提示符与Python不同,它用颜色标出了不同类型的程序和数据,在输入命令的过程中,可以通过按“Tab”键补全命令,还支持按“上”键,调出以往输入的命令。相对于Python命令行方便很多。

2.3.3 Spyder

Spyder是Python作者开发的一个简单的Python集成开发环境,开发者可以在Spyder中编写和运行程序。

首先,打开Spyder程序:开始菜单->所有程序->Anaconda->Spyder,打开的Spyder界面如图2.8所示:

图2.8 Spyder界面

Spyder界面主要包含三部分,左边是程序编辑区,开发者在左侧编写程序;右侧上部是对象变量文件浏览区,右侧下部是命令窗口区,它提供ipython的交互界面,开发者在此处以交互模式输入Python代码,此处同时显示左侧程序运行结果。

下面来编写第一个Python程序,在左侧区域加入代码:

 01 print("aaa")

输入代码后,点击上方快捷菜单中的绿色箭头运行这段程序,在右下的交互界面中显示了程序的运行结果“aaa”。

2.3.4 Jupyter Notebook

Jupyter Notebook开始叫IPython Notebook,它是一个交互式的编程界面,初期只支持Python,后来逐渐发展,现已支持四十多种编程语言。

Jupyter在后台开启服务,开发者通过浏览器与服务连接,可在浏览器中编写程序和查看运行结果。它的优点是可以在某一台机器上安装Python环境,而在同一网络的任意一台机器上都可以通过IP地址和端口连接该环境,编写Python程序,而无需在每一台开发机器上安装Python环境。

相对其它编程工具,Jupyter Notebook界面看起来简洁大方,且启动速度快。其中间的主要区域用于编写程序,运行结果显示在程序下方。本教程中后续的例程都使用Jupyter Notebook编写。

Jupyter Notebook与其它Python程序开发软件不同的是,一般Python程序扩展名为“.py”,而Notebook中Python程序默认的格式是“.ipynb”。这种格式不只支持python代码,还能加入格式丰富的文字、图片、以及记录程序运行结果。同时它也支持导出纯代码格式的“.py”文件。

需要注意的是:有些浏览器不支持Jupyter Notebook,建议使用Firefox浏览器开发,并将Firefox设置成默认浏览器。

打开Jupyter Notebook程序:开始菜单->所有程序->Anaconda->Jupyter Notebook,此时跳出后台服务框的同时,默认浏览器也被开启。Jupyter有两种界面,一种是列表界面,一种是程序编辑界面。列表界面如图2.9所示。

图2.9 Jupyter Notebook列表界面

浏览器中显示了文件目录列表,第一次使用时可以用右上边的Upload上传代码文件,或者使用New->Python 3创建程序文件,本例中创建了一个Python程序,程序编辑界面如图2.10所示。

图2.10 Jupyter Notebook程序编辑界面

编程界面上菜单支持的功能很多,不能一一列举。几个最常用的功能在图2.10中用绿色字符标出。

一般编程工具都有颜色提示,比如在Jupyter Notebook中Python提供的关键字(像while, import)用绿色,符号为粉色,字符串为红色,通过颜色可识别打字引起的错误。当光标停在一个括号上时,括号的另一半颜色也随之改变,这样可以查看括号是否成对出现。Jupyter还支持代码自动补全功能,按Tab键即可使用。

图2.10中的每个灰色方格都是Cell单元,它是Notebook中的基本元素。通过Insert菜单可添加新的单元。单元分为两种:Markdown单元(标记语言)和代码单元。

Markdown单元:一般用于编写注释和说明信息,文本格式、插入链接、图片甚至数学公式等数据,一般使用Markdown 的语法编写,纯文本也可正常显示。

代码单元:代码单元左边有“In [ ]:”的序列标记,方便查看代码的执行次序。其运行结果显示在该单元下方。

单元有编辑模式和命令模式,命令模式时单元左侧显示蓝线,编辑模式时左侧显示绿线。按Enter键切换到编辑模式,按Esc键切换到命令模式。编辑模式一般用于修改单元内容,命令模式用于对整个单元进行操作,如添加单元、删除单元等,比如用Shift+L快捷键控制是否显示行号,用Shift+Enter执行当前单元中的代码。


课后练习:

练习二:用Jupyter编写程序,显示字符串“aaaa”。

2.4 思维训练

我们常说“学完之后,都还给老师了”。这也是学习中最常见的问题:当时的确学会了,过一段时间记得好像学过,却忘记了具体内容。它可能受到以下几种因素影响:

理论脱离实际

大学理工科都需要学微积分,同学说“这有什么用?我买菜还积个分吗?”的确后来很少有人在生活中用到高等数学。越是抽象,离生活越远,越难理解,更难被记住。原因可能是难度大,也可能因为使用得太少了。

学习编程也是一样,很多课程中,老师搭建好环境,学生主要在编程工具中操作,学习偏重于基础和理论,可以拿它“玩”、“做展示”,却没有渗透进日常生活之中。开发程序是一项综合技能,涉及查资料、安装软件、制作图片、编写界面,配置环境,分析数据,调试程序,以及将结果呈现给他人,以及综合使用知识的能力,后面课程也会逐步讲解。

本讲中的安装软件、查资料等技能在日常生活中也很常用,比如养成用手机或者电脑查资料的习惯:游泳、养鱼、做饭都可以在网上学习,天天使用想忘记都很困难。

读者在学习的过程中一定要边学边用,无论是配置环境的例程还是程序例程都要跟着做一遍,并且尽量使用它解决生活中的问题。

复习

日常生活中可能遇到非常多的知识和技能,全记住需要大量的存储空间,查找也将非常耗时。大脑一般会记住那些重要的,而忽略不太重要的。

在学习时,知识进入了短时记忆,可以存储几分钟到几天的时间,而只有少部分短时记忆被转存在长时记忆之中,这部分通常是反复使用的。对于日常能用到的知识和技能,每用一次都会加深印象。还有一些,比如背单词,没有可用的语言环境反复训练,就需要利用复习的方法反复刺激,才能形成长时记忆。

提炼

提炼又可以分成简化、归纳、总结规律等等。

  • 简化
    简化问题是把重要部分从千头万绪中清理出来。比如读文章时,不可能记住每一个字;学习相对复杂内容和新内容时,读完之后大脑往往一片空白。建议一边看一边划重点,并总结每一段的大意。阅读文章时需要划重点,做数学应用题时也一样,概括之后脑中记忆的都是关键点,查找起来更加迅速,同时也保留了大量空间用于联想和思考。
  • 归纳
    经过层层简化后,梳理关键点之间的关系,形成树型或网状的知识结构,这也是总结和建构知识体系的过程。大段的文字如果被整理成1.2.3,(1)(2)(3)带顺序和层次的简化版本,往往更容易被记忆以及联想。
    就像整理衣橱一样,把知识放到适当的位置,再打上标签,之后使用时就能方便地找到。同时也与类似的问题建立连接,与已有知识建立连接,使新知识更容易被联想,提供多种方式被调出。
  • 找规律
    在解决复杂问题时,难免“卡壳”,解决了问题之后,需要反思,在会与不会之间,到底被“卡”在了哪个点。然后总结规律,并将规律用在其它的问题之中。只有会用才是真的学会了。

有时候我们把学习当成打卡,做完就完,多一眼都不看。实际上我们的角色不仅是学习者,同时也是检查员。一个人做两个人的工作也有难度,也需要用一段时间培养习惯。因此,从本讲开始,每一课都请读者总结本讲学习的内容,并列举其用途。

课后练习:

练习三:总结本讲学习的内容,并列举三种用途。

2.5 本课小结

本课的学习重点除了熟悉Windows操作系统,安装软件之外,还包括学习使用浏览器搜索,学习这项技能后,如果遇到无法解决的问题,可以通过百度搜索在网上寻找答案。

2.5.1 单词

对于小读者来说,在下载安装软件时遇到的最大问题是:不熟悉计算机操作相关的英文单词及它们在计算机领域的意思,最好能在学习过程中背下来,本讲需要掌握的英文单词如表2.1所示。

表2.1本讲需要掌握的英文单词

2.5.2 习题答案

1. 练习一:安装软件Firefox浏览器。

  • 第一步、查看本机是否已安装Firefox浏览器:点击桌面上的“计算机”图标,选择其窗口上方的“打开控制面板”->程序->卸载程序,即可打开“程序和功能界面”,查看是否有名为“Firefox的程序”,如果已经存在,则不需要安装。如果想尝试安装过程,可以先卸载再安装。
  • 第二步、用浏览器打开百度:www.baidu.com
  • 第三步、在输入框中输入关键字:“Firefox 下载”,注意:把需要搜索的内容切分成词,词间用空格分隔;点击右侧的“百度一下”开始搜索。
  • 第四步:点击搜索返回的网址列表,在网页中点击其中的“下载Firefox”,并在文件下载框中点选择“运行”。
  • 第五步:按提示安装,直到FireFox浏览器安装成功并正常启动。

2. 练习二:用Jupyter编写程序,显示字符串“aaaa”。

图2.11 显示字符串

3. 练习三:总结本讲学习的内容,并列举三种用途。

本题答案比较灵活,主要目标是养成梳理问题的习惯,只有包括主要元素,怎么组织都可以。下图为小李同学用xmind绘制的思维导图,笔者认为安装部分过于细化,但为保留小李同学作业的完整性,未做修改。

图2.12 本课内容总结



少儿Python编程_第一讲:计算机系统

少儿Python编程_第一讲:计算机系统

本次课主要讲解一些计算机和操作系统相关的基础知识。
日常看到的计算机有台式机(左侧)和笔记本电脑(右侧)两种,如图1.1所示:

图1.1 常见的计算机


计算机需要软件和硬件两部分结合才能正常工作,硬件是由电子、机械、光电元件组成的物理装置,看得见摸得着。软件是有特定功能的数据和指令的集合,软件实现了具体的功能,编写软件就是编程。

1.1 计算机硬件

计算机硬件又可以分为主机和外部设备两部分,主机是图1.1左图中的黑色“机箱”,打开机箱,可以看到:主板、CPU、内存、硬盘、电源等计算机必备的硬件,它们之间通过数据线和插槽连接,如图1.2所示:

图1.2 主机硬件
  • 主板:主板被固定在机箱之内,一般是一块矩形的电路板,主板上面有多个插槽,用于连接其它硬件。有的主板还集成了网卡(负责网络传输)、显卡(用于连接显示器)、声卡(用于输出声音)等硬件。主板如图1.3所示:
图1.3主板示意图
  • CPU:中央处理器简称CPU,是一块超大规模集成电路,它是计算机运算和控制的核心部件。CPU的处理速度是计算机性能的重要指标之一。它被安装在图1.3的CPU插座中,只有半张扑克牌大小,CPU在工作的时候会产生大量的热,如果不将这些热量及时散发出去,轻则导致死机,重则可能烧毁CPU。一般同时安装CPU散热器(风扇),用于快速将CPU的热量传导出来并吹到附近的空气中去,起到降温的作用。CPU如图1.4所示。

图1.4 CPU图片


  • 内存:内存也被称为内存储器或主存储器,计算机在运行时,CPU把需要运算的数据调到内存中进行运算,运算完成后CPU再将结果传送出来,内存保证了计算机的稳定运行。
图1.5内存图片


  • 硬盘:硬盘是计算机的主要存储设备,照片、文档及其它各种软件数据都被存储在硬盘上。与内存不同的是,关机后硬盘上的数据依然存在(由于硬盘属于存储介质,也有一些书籍将其归类为外部设备)。
图1.5硬盘图片


外部设备是主机的扩展,它包括输入设备和输出设备,像:鼠标、键盘、绘图板都属于输入设备,而显示器、打印机属于输出设备,它们通过与主机连接在一起扩展主机的功能。

笔记本电脑将主机和最重要的外部设备集成在一起,占空间更小,一台小小的笔记本即可完成计算机的所有工作,但是性能往往不如台式机高,和同样的配置的计算机相比,价格也较贵。

课后练习:(练习答案见本讲最后的小结部分)

练习一:如果有条件,请小读者在家长的带领下,拆开主机机箱,找到并指出其中的主板、内存、CPU、磁盘;想一想,如果更换内存或者硬盘应该怎么操作;顺便打扫一下机箱内部。

(注意:请小读者在家长的带领下操作,一定要先拔掉电源!!!)

1.2 计算机软件


计算机软件,也称为软件,一般包括程序和数据,程序描述了计算任务的处理对象和处理方法。

软件又分为系统软件和应用软件。智能手机和计算机一样也包括系统软件和应用软件,如OPPO、VIVO、华为手机一般使用安卓系统,而苹果手机一般使用iOS系统软件,也称操作系统。它位于硬件和应用软件之间,如图1.6所示,它向下控制硬件设备(如CPU、内存、蓝牙设备),使它们协调工作,向上支持应用软件和监控维护整个系统的运行(如显示图形界面、切换应用)。应用软件实现具体实用的功能,比如:运行在手机上的微信、游戏、阅读软件等等。不同的系统软件上运行的应用软件也不一样,比如:在苹果手机和华为手机上虽然都能使用微信,功能虽然差不多,但却是使用不同工具编写的不同软件。

图1.6软硬件结构图


计算机最常用的操作系统是Windows,像Windows 10,Windows 7是Windows的不同版本,此外,还有苹果电脑常用的macOS操作系统、服务器常用的Linux操作系统等等。一般情况下,计算机同一时间只开启一个操作系统,但可以启动多个应用软件,比如一边播放音乐一边玩游戏。

1.3 Windows文件存储

本节将Windows 7作为默认的计算机操作系统,介绍Windows的文件存储。

当输入一段文字或者修改图片后选择保存时,数据文件存储在硬盘上,在关机之后也不会丢失,那么它保存在什么位置,下一次又如何打开它,如何通过微信或者邮件把文件发送给他人呢?

1.文件和文件夹

无论使用哪一种操作系统,都会用到文件和文件夹(也称目录)的概念。文件用于存储具体的数据,比如文字、图片、程序都被保存成文件。文件名一般由两部分组成,例如:“说明书.doc”,其中的“说明书”是主文件名,时给文件命名需要注意:起有意义的名字,养成起名和及时存盘的好习惯,文件名中的“doc”是扩展名,用于区分文件的不同类型。主文件名和扩展名之间用“.”分隔。

文件夹用于管理计算机中的文件,文件夹本身并不存储具体数据,打开Windows桌面上的“计算机”图标,如图1.7所示,其中黄色的小图标代表文件夹,文件夹中又可以包含其它的文件或文件夹。整体成树型结构,左侧为树根,向右侧逐渐展开枝叶,文件分级存储在各个文件夹中。

图1.7 文件目录示意图

请读者培养管理文件的好习惯,比如:把同一件工作对应的文件都保存在同一文件夹下,或者把同一类型的数据都保存在同一文件夹下。

2.文件大小

有时手机或计算机会提示存储空间不足,需要删除一些文件,那么到底哪些文件占空间大,删除哪些文件更有效呢?先来看看文件大小的计量单位。

位(bit)是计算机存储数据的最小单位,每一位可以存储一个值:0或者1,一个字节可以存储8位,1KB等于1000字节,1MB(兆)等于1000K,1GB等于1000M。GB就是我们看到广告中常说的“10元10GB国内流量包”中的单位,那么请读者计算一下,10GB等于多少“位”呢?

10GB = 10 x 1000 x 1000 x 1000 x 8 = 80000000000,答案是:800亿位。

一般安装一个软件,需要几MB到几十MB的存储空间,一张普通照片需要几MB存储空间,一段视频可能几十MB,而文字占空间较小,一本几十万字的纯文字书籍只需要占几百KB空间,微信语音聊天每秒1K左右……这样下一次存储空间不足时,读者就可以根据文件的大小选择先删除不需要的大文件了。在计算机的文件上点右键,选择右键菜单中的“属性”选项,可以看到文件所占的空间大小。

3.本地磁盘

上一节中讲到数据保存在硬盘上,一台计算机通过插槽连接一块或者多块硬盘,一块硬盘又可以被分成一个或多个分区,图1.7中,计算机只插入了一块硬盘,且被分成了单个分区:本地磁盘(C:),所有的文件都被存储在C盘之中。

4.我的文档

保存文件时,一般默认保存到“我的文档”文件夹,从图1.7中看到,“库->文档”并不在“本地磁盘”之下,那么它到底存储在硬盘的什么位置呢?在“文档”上点击右键,选择“属性”,结果如图1.8所示,可以看到“我的文档”也存放在C盘上,其在Windows 7中的具体路径是C:\Users\administrator,其中user的意思是用户,administrator意思是管理员,它是这台机器当前登录的用户名。

图1.8“我的文档”存储位置

课后练习:

练习二:如果本月手机套餐流量为100M,请计算大概能传几张相片,语音聊天多长时间。

1.4 思维训练

上面介绍了计算机系统和Windows的文件存储,希望读者在学习之后梳理学习的知识点,以及知识点之间的关系。本节将介绍一些相关的学习方法。

1.4.1 思维导图

思维导图是一种实用的思维工具,它由一个思维中心开始,逐渐向发散。使用思维导图可以将关键词分层,并在关键词之间的建立连接。本节将介绍思维导图的功能及用法,请读者使用它整理和积累所学的知识。

下面举一个简单的例子,假设去超市购物,列出购物清单,建立如图1.9所示的思维导图,把需要购买的商品逐层分类。

图1.9 购物思维导图


思维导图在纸上就可以绘制,但在纸上画的思维导图需要一开始就安排好内容和位置,在绘制过程中删减内容或者字写得不够工整,都会影响表达的效果或者需要重画。建议用计算机绘制思维导图,上例中的思维导图使用了线上工具爱莫脑图,用浏览器打开网页即可直接使用,无需安装软件。网址是:mindmap.airmore.cn/gues(注意使用右键添加新的元素)。

绘制思维导图时需要注意,不要在一张图中列出太多的内容和细节,思维导图与作文提纲、PPT幻灯片一样,思路比内容更加重要。

课后练习:

练习三:画出计算机系统的思维导图(包含软件和硬件)。

1.4.2 记忆和积累

人的记忆分成长时记忆和短时记忆,长时记忆能记住几天或者几年前发生的事,就像硬盘;而短时记忆只能记住几分钟或者几秒钟内发生的事,短时记忆能存储的内容是非常有限的,就像是内存。因此,需要把每一课所有的内容通过复习存储到长时记忆中去,下一次才有空间存储和思考新的知识。

思维的中断不只来自于外部干扰,比如有人突然来敲门;更多时候来自内部干扰,当我们专注于一件事时,短时记忆中存储的全都是它相关的东西,常称之为环境,突然去查找或者切换到另一事件,就要把之前的重要内容先保存好,换上另一件事,做完后再把旧的环境切换回来,很多细节就丢失了。比如读同一本小说的中文版是休闲娱乐,而读英文版或者文言文要累得多,很难读下去,这都是由于大脑的思维负担过重。

编程语言也是一种语言,就像学英语一样,常用单词一定要背会,否则,后面读文章的时候,对很多单词不记得或者模棱两可,理解起来就会越来越困难,中途查书或者查字典,不停打断思路,就没有办法思考复杂的问题,花的时间也多得多。

所以,请从未接触过计算机编程的读者,尤其是小读者一定要在学习下一讲之前背会本讲相关单词。微信小程序和手机都提供一些背单词用的软件,建议读者使用工具背单词。养成利用工具的习惯,事半功倍。

学习新知识的时候,有人好像一学就会,很“聪明”,而很多情况下“聪明”也能被培养。无论是学习编程还是其它科目,前期基础越差,后期就学得越慢,学习效果也越差,问题成倍增长,看起来就不那么“聪明”了。

1.5 本课小结

1.5.1 单词

本讲需要掌握的单词如表1.1所示:

表1.1 英文单词列表

1.5.2 参考答案

1.练习一:如果有条件,请小读者在家长的带领下,拆开主机机箱,找到并指出其中的主板、内存、CPU、磁盘,看看它们如何连接;想一想,如果更换内存或者硬盘应该怎么操作;顺便打扫一下机箱内部。

小读者可以在家长的指导下拆装内存和硬盘,在拆装的过程中学习使用不同大小的一字和十字螺丝刀,以及拧螺丝时左松右紧的习惯用法。在以后需要更换硬盘或者内存时也可以自己操作。同时也培养一下爱劳动的好习惯。

图1.10清洁机箱内部

2.练习二:画出计算机系统的思维导图。

思维导图主要用于帮助记忆,本题的正确答案不只一个,图1.11为小李同学绘制的思维导图。

图1.11 计算机系统思维导图


3.练习三:如果本月手机套餐流量为100M,请计算大概能传几张相片,语音聊天多长时间。

如果语音聊天,可聊100000秒,约27.8小时。
如果传5MB一张的相片,可传20张。