交互提示模式下编写代码
也许最简单的运行Python程序的办法就是在Python交互命令行中输入这些程序。有多种办法能够开始这样的命令行:在IDE中、系统终端中等。具体相关PATH环境变量的设置,此处不再赘述
DOS窗口:
IDLE(GUI)
交互式运行代码
键入一行代码,enter键执行
退出交互会话,Unix、Linux系统:Ctrl+D、exit();Windows、Mac DOS:Ctrl+z;IDLE GUI:Ctrl+D、exit()
也可以键入多行代码输出,注意代码缩进,代码键入完毕,需要按两次回车
为什么使用交互提示模式
交互提示模式根据用户的输入运行代码并响应结果,但是,它不会把代码保存到一个文件中,尽管这样,交互模式依然是体验语言和测试编写的一个号选择
1、实验
由于代码时立即执行的,交互提示模式变成了实验这个语言的绝佳的地方。实际上,当你对一段Python代码的运行有任何疑问的时候,马上打开交互命令行并实验,看看会发生什么。这种方式不会带来任何破坏。而且,当你执行一条错误的代码时,没什么大不了,你还能收到一条报错消息,指出问题所在
2、测试
除了充当学习语言的体验工具,交互式编译器也是测试已经写入到文件中的代码的好地方。
使用交互提示模式
有几点需要注意
- 只能够输入Python命令,要输入系统命令,需要导入os模块,然后用os.system来调用
- 在文件中打印语句是必须的。在交互解释器中自动打印表达式的结果,不需要在交互模式下输入完整的打印语句。但是在文件中,必须使用print语句进行输出
- 交互提示模式一次运行一条语句
系统命令行和文件
尽管交互命令行对于实验和测试来说都很好,但它也有一个很大的缺点:Python一旦执行了输入的程序后,它们就消失了。在交互模式下输入的代码时不会保存在文件中的,因此为了能够重新运行,不得不再次输入。复制-粘贴也只能一次一行,很不方便,如果是比较大的程序的话。
为了能够永久的保存程序,需要在文件中写入代码,这样的文件通常叫做模块。模块是一个包含了Python语句的文本文件。一旦编写完成,可以让Python解释器多次运行这样的文件中的语句,并且以多种方式去运行:通过系统命令行、通过点击图标等。无论它是如何运行的,每一次当你运行模块文件时,Python都会从头至尾地执行模块文件中的每一条代码。
这一部分的术语可能会有些变化。如,模块文件常常作为Python写成的程序。也就是说,一个程序是由一系列编写好的语句组成,保存在文件中,从而可以反复执行。可以直接运行的模块文件往往也叫做脚本(一个顶层程序文件的非正式说法)。有些人将"模块"这个说法应用于被另一个文件所导入的文件(其实就是一个程序执行需要调用另一个程序的某些功能,因此需要import该程序,后面会有介绍)。
下面我们来看如何运行输入至模块文件的代码,我们先了解一种最基本的方法运行文件:通过在系统提示模式下的Python命令行,列出它们的名字。尽管对某些人来说这似乎有点粗糙简单,但对于很多程序员来说,一个系统shell命令行窗口加上一个文本编译器窗口,这就组成了他们需要的一个集成开发环境的主要部分。
1、第一段脚本
#A first Python script
import sys
print(sys.platform)
print(2 ** 100)
x = 'hello!'
print(x * 8)
这个文件:
- 导入了一个Python模块,目的获取系统平台的名称
- 运行了3个print函数调用,以显示脚本的结果
- 使用了一个名为x的变量,创建的时候对其赋值,保存了一个字符串对象
文件中#开头的行为注释,运行时,PVM不会执行这些内容,注释是为了增强代码的可读性。
2、使用命令行运行文件
一旦保存了这个文本文件,可以将其完整的文件名作为一条Python命令的第一个参数,在系统命令行窗口中输入来执行它:
我们也可以把输出结果重定向到一个文件中,保存起来以备以后查看,这个只是流重定向,用来控制文本的输入和输出,与Python其实没有直接关系,Python只是支持这个功能而已:
在较新的Windows版本上,可以只输入脚本的名字就可以执行。新的Windows系统使用Windows注册表找到用哪个程序来运行一个文件,不需要用户显式指定:
3、使用命令行和文件
有几个注意的地方(老司机一般不会犯):
- 注意Windows上的默认扩展名
- 在系统提示符模式下使用文件扩展名,导入时不使用文件扩展名
- 文件中需要使用print函数,才会捕捉结果并输出
4、Unix可执行脚本(#!)
如果在Python、Linux及其他Unix类型上使用Python,可以将Python代码编程为可执行程序,就像使用shell语言编写的csh或ksh程序一样。这样的脚本往往叫做可执行脚本。简言之,Unix风格的可执行脚本包含了Python语句的一般文本文件,但是有两个特殊的属性。
- 它们的第一行是特定的。脚本第一行往往以字符#!开始,其后紧跟Python解释器的路径
- 它们往往都拥有可执行权限。脚本文件往往告诉操作系统它们可以作为顶层程序执行,拥有可执行的权限
#!/usr/bin/env python
print("hello world!")
文件顶端特定的一行告诉系统Python解释器保存在哪。从技术上来看,第一行是Python注释,为了提高代码的可读性。但是当第一行和这个文件一样的话,它就有了特殊的意义,因为操作系统使用它找到解释器来运行文件其他部分的程序代码。而且,这个文件名可以不以.py结尾也没关系。如果赋予其可执行权限,就能够在shell中如一个二进制文件一样运行它。
Windows下,可能不需要在文件顶部加特定的#!注释,也不需要赋予其可执行权限。
5、点击图标文件
在Windows下,注册表使通过点击图标打开文件更容易。当Python程序文件点击打开时Python会自动注册为所运行的那个程序。正因如此,才能通过鼠标点击图标来运行程序
在非Windows系统中,也能够使用相同的技巧,但是图标、浏览器、文件管理器的原理以及很多方面都有少许不同。例如,在一些Unix系统中,也许需要在文件管理器的GUI中注册.py的扩展名,从而可以使用前面说的#!技巧使脚本成为可执行的程序,或者使用应用程序关联文件的MIME类型或通过编辑文件、安装程序等命令,或者使用其他的工具。
6、input的技巧
不幸的是,在Windows系统中,点击文件图标的结果也许不是特别令人满意,点击后"一闪而过",而不是我们期盼的结果。这并不是bug,但是需要做某种操作才能使Windows处理打印结果。
默认情况下,Python会弹出一个黑色DOS终端窗口作为文件的输入或输出。如果脚本打印后退出,也就是说,它仅是打印后退出终端窗口显示,然后文本在这里打印,但是在程序退出时,终端窗口关闭并消失。除非你反应非常快,或机器运行非常慢,否则看不到任何输出。
幸运的是,这样的问题很好解决。如果需要通过图标点击运行脚本,脚本输出后暂停,可以简单的在脚本的最后添加内置input函数的一条调用语句。一般来说,input读取标准输入的下一行,如果还没有得到一直等待输入。在这种情况下执行的实际效果就是让脚本暂停,直到键入回车为止。
7、图标点击的其他限制
即使使用了input技巧,点击文件图标仍有一定的风险。你可能看不到Python的错误信息。如果脚本出现了错误,错误信息的文字将会写在弹出的终端窗口上:这个窗口马上就会消失。而且在调用input之前脚本就已经停止。
由于这些限制,最好将点击图标看做是在程序调试结束后或已经将其输出写入到一个文件之后,启动运行程序的一种方法。
模块导入和重载
前面我们的脚本用到了一个import sys,导入模块。现在先简单看下这个名词的意义。
用简单的术语讲,每一个以扩展名.py结尾的Python源代码文件都是一个模块。其他的文件可以通过导入一个模块读取这个模块的内容。导入从本质上讲,就是载入另一个文件,并且能够读取那个文件的内容。一个模块的内容通过这样的属性能够被外部世界使用。
这种基于模块的方式使模块变成了Python程序架构的一个核心概念。更大的程序往往以多个模块文件出现,并且导入了其他模块文件的工具。其中的一个模块文件设计成主文件,或叫做顶层文件(就是启动后能运行整个程序的文件)。
关于这种模块架构的问题,后面我们再探究。此处我们关心的是被载入的文件通过导入操作最终可运行代码。故,导入文件是另一种运行文件的方法
默认情况下,只是在每次会话的第一次运行,在第一次导入后,其他的导入都不会再工作。这是有意设计的结果。导入是一个开销很大的操作,以至于每个文件、每个程序运行不能够重复多余一次。
但是如果真的想在同一次会话中再次运行文件,需要调用imp标准库中的reload函数
此处from语句直接从模块中导入某个需要的功能。reload函数载入并运行了文件最新版本的代码。这允许你在当前交互会话的过程中编辑并改进代码。
reload函数希望获得的参数是一个已经加载了的模块对象的名称,所以如果在重载之前,确保已经成功导入了这个模块。注意,reload函数需要将模块对象名称用圆括号括起来,import不需要。因为reload是一个被调用的函数,import是一个语句
1、模块的显要特性:属性
导入和重载提供了一种自然的程序启动的选择,因为导入操作将会在最后一步执行文件。从更宏观的角度看,模块扮演了一个工具库的角色。从一般意义来说,模块往往就是变量名的封装,被认作是命名空间。在一个包中的变量名就是所谓的属性:也就是说,属性就是绑在特定的对象上的变量名(就像一个模块)
在典型的应用中,导入者得到了模块文件中在顶层所定义的所有变量名。这些变量名通常被赋值给通过模块函数、类、变量以及其他被到导出的工具。这些往往都会在其他文件或程序中使用。表面上来看,一个模块文件的变量名可以通过两个Python语句读取:import和from,以及reload调用。
下面我们来看一个示例
用文本编辑器创建一个名为myfile.py的单行Python模块文件,内容是:title = "The Meaning of Life"。当文件导入时,它的代码运行并生成了模块的属性。这个赋值语句创建了一个名为title的模块的属性。
可以通过两种不同的方法从其他组件获得这个模块的title属性。第一种,可以通过使用一个import语句将模块作为一个整体载入,并使用模块后跟一个属性名来获取它:
一般来说,这里的点表达式代表了object.attribute的语法,可以从任何的object中取出器任意的属性,并且这是Python代码中的一个常用操作。这里我们用它去获取模块myfile中一个字符串变量title,也就是获取myfile模块的title属性:myfile.title。
第二种,可以通过from module import attribute这样的语句从模块中获得(实际上是复制)变量名(属性):
from和import很相似,只不过增加了对载入组件的变量名的额外赋值。从技术上讲,from复制了模块的属性,以便属性能够成为接收者的直接变量。
无论使用的是import还是from去执行导入操作,模块文件myfile.py的语句都会执行,并且导入的组件在顶层文件中获得了变量名的读取权。
2、模块和命名空间
模块导入时一种运行代码文件的方法,模块同样是Python程序最大的程序结构。
一般来说,Python程序往往由多个文件模块构成,通过import语句连接在一起。每个模块文件是一个独立完备的变量包,即一个命名空间。一个模块文件不能看到其他文件定义的变量名,除非它显式导入了那个文件,所以模块文件在代码文件中起到了最小化命名的冲突作用。因为每个文件都是一个独立完备的命名空间,即使它们拼写相同的情况下,一个文件中的变量名也不会与另一个文件中同名的变量名起冲突。
3、import和reload使用注意
一旦我们知道通过import和reload运行文件,就会倾向于仅使用这个方法,忽略了能够运行最新版本代码的其他选择(如,图标点击、IDLE菜单选项及命令行)。这会让人变得困惑:你需要记住是何时导入的,才能知道能不能reload,需要记住到调用reload时需要括号,让代码的最新版本运行时首先使用reload。此外,reload是不可传递的,重载一个模块的话只会重载该模块,而不能够重载该模块所导入的任何模块,因此,有时候必须reload多个文件。
介于这些复杂问题,从现在起就要避免使用import和reload启动程序。其实有很多简单的运行代码最新版本的办法,后面我们会了解并使用。
使用exec运行模块文件
exec是从交互模式启动文件而不必导入以及随后的重载的一种运行文件最新版本的方法。
exec(open('module.py').read())
exec调用有类似import的效果,但是,它从技术上不会导入模块,默认情况下,每次以这种方式调用exec的时候,它都会重新运行文件,就像我们把文件内容粘贴到了exec的参数里。因此呢,exec每次可以运行文件最新版本
缺点是,由于exec工作机制就好像在调用它的地方粘贴了代码,和前面提到的from一样,对于当前正在使用的变量有潜在的默认覆盖的可能。相反,基本的import语句每个进程只运行文件一次,并且会把文件生成到一个单独的模块名称空间中,以便它的赋值不会改变你的作用域中的变量。为模块名称空间分割所付出的代价是,在修改后要重载。