python基础教程运行程序_Python基础教程:你的第一个 Python 程序(3)

异常#

异常在 Python 中无处不在。事实上在标准 Python 库里面的每个模块都使用它们,而且在很多不同情形下, Python 自身也会抛出异常。贯穿这本书,你会反复的看到它们。

什么是一个异常?通常情况下,它是一个错误,提示某个东西出问题了。(不是所有的异常都是错误,但目前来说别担心那个) 某些程序语言鼓励对错误返回代码的使用,你可以对它进行检查。 Python 鼓励对异常的使用,你可以对它进行处理。

当一个错误发生在 Python Shell 里面的时候,它会打印一些关于这个异常以及它如何发生的详细信息,就此而已。这个被称之为一个 未被处理

的异常。在这个异常被抛出的时候,没有代码注意到并处理它,因此它把它的路径冒出来,返回到 Python Shell

的最顶层,输出一些调试信息,然后圆满结束。在这个 Shell 中,这没什么大不了的,但是如果在你的实际 Python

程序正在运行的时候发生,并且对这个异常没有做任何处理的话,整个程序就会嘎的一声停下来。可能那正是你想要的,也可能不是。☞不像 Java, Python 函数不声明它们可能会抛出哪些异常。它取决于你去判断哪些可能的异常是你需要去捕获的。

一个异常不会造成整个程序崩溃。不过,异常是可以被处理的。

有时候一个异常是真正地由于你代码里面的一个 bug 所引起的(比如访问一个不存在的变量),但有时候一个

异常是你可以预料到的东西。如果你在打开一个文件,它有可能不存在。如果你在导入一个模块,它可能没有被安装。如果你在连接到一个数据库,它有可能是无效

的,或者你可能没有访问它需要的安全认证信息。如果你知道某行代码可能抛出一个异常,你应该使用 try...except 块来处理这个异常。☞Python 使用 try...except 块来处理异常,使用 raise 语句来抛出异常。 Java 和C++使用 try...catch 块来处理异常,使用 throw 语句来抛出异常。

这个 approximate_size() 函数在两个不同的情况下抛出异常:如果给定的size的值大于这个函数打算处理的值,或者如果它小于零。if size 

抛出一个异常的语法足够简单。使用 raise 语句,紧跟着异常的名称,和一个人们可以读取的字符串用来调试。这个语法让人想起调用的函数。(实际上,异常是用类来实现的,这个 raise 语句事实上正在创建一个 ValueError 类的实例并传递一个字符串 "number must be non-negative" 到它的初始化方法里面。但是,我们已经有些超前了!)☞你不需要在抛出异常的函数里面去处理它。如果一个函数没有处理它,这个异常会被传递到它的调用函数,然后那个函数的调用函数,等等“在这个堆栈上面。” 如果这个异常从来没有被处理,你的程序将会崩溃, Python 将会打印一个 “traceback” 的标准错误信息,并以此结束。这也可能正是你想要的,它取决于你的程序具体做什么。

捕获导入错误#

其中一个 Python 的内置异常是 ImportError,它会在你试图导入一个模块并且失败的时候抛出。这有可能由于多种原因引起,但是最简单的情况是当在你的 import 搜索路径里面找不到这个模块的时候会发生。你可以用这个来包含可选的特性到你的程序中。例如, 这个 chardet 库 提供字符编码自动检测。也许你的程序想在这个库存在的时候使用它,但是如果用户没有安装,也会优雅地继续执行。你可以使用 try..except 块来做这样的事情。try:  import chardetexcept ImportError:  chardet = None

然后,你可以用一个简单的 if 语句来检查 chardet 模块是否存在:if chardet:  # do somethingelse:  # continue anyway

另一个对 ImportError 异常的通常使用是当两个模块实现了一个公共的API,但我们更想要其中一个的时候。(可能它速度更快,或者使用了更少的内存。) 你可以试着导入其中一个模块,并且在这个模块导入失败的时候退回到另一个不同的模块。例如, XML 的章节谈论了两个模块实现一个公共的API,叫做 ElementTree API。 第一个,lxml 是一个第三方的模块,你需要自己下载和安装。第二个, xml.etree.ElementTree 比较慢,但属于 Python 3 标准库的一部分。try:    from lxml import etreeexcept ImportError:    import xml.etree.ElementTree as etree

在这个 try..except 块的结尾,你导入了某个模块并取名为etree。由于两个模块实现了一个公共的API,你剩下的代码不需要一直去检查哪个模块被导入了。而且由于这个一定会被导入的模块总是叫做etree,你余下的代码就不会被调用不同名称模块的 if 语句所打乱。

Unbound 变量#

再看看 approximate_size() 函数里面的这行代码:multiple = 1024 if a_kilobyte_is_1024_bytes else 1000

你从不声明这个multiple变量,你只是给它赋值了。这样就可以了,因为 Python 让你那样做。 Python 将不会让你做的是,引用了一个变量,但从不给它赋值。这样的尝试将会抛出一个 NameError 的异常。>>> xTraceback (most recent call last):  File "", line 1, in NameError: name "x" is not defined>>> x = 1>>> x1

将来有一天,你会因为这个而感谢 Python 。

所有的东西都是区分大小写的#

Python 里面所有的名称都是区分大小写的:变量名、函数名、类名、模块名称、异常名称。如果你可以获取它、设置它、调用它、构建它、导入它、或者抛出它,那么它就是区分大小写的。>>> an_integer = 1>>> an_integer1>>> AN_INTEGERTraceback (most recent call last):  File "", line 1, in NameError: name "AN_INTEGER" is not defined>>> An_IntegerTraceback (most recent call last):  File "", line 1, in NameError: name "An_Integer" is not defined>>> an_inteGerTraceback (most recent call last):  File "", line 1, in NameError: name "an_inteGer" is not defined

等等。

运行脚本#

Python 里面所有东西都是对象。

Python 模块是对象,并且有几个有用的属性。在你编写它们的时候,通过包含一个特殊的仅在你从命令行运行 Python 文件的时候执行的代码块,你可以使用这些属性容易地测试你的模块。看看 humansize.py 的最后几行代码:if __name__ == "__main__":    print(approximate_size(1000000000000, False))    print(approximate_size(1000000000000))☞像C语言一样, Python 使用 == 来做比较,用 = 来赋值。不同于C语言的是, Python 不支持内嵌的赋值,所以没有机会出现你本以为在做比较而且意外的写成赋值的情况。

那么是什么使得这个 if 语句特别的呢? 好吧,模块是对象,并且所有模块都有一个内置的属性 __name__。一个模块的 __name__ 属性取决于你怎么来使用这个模块。如果你 import 这个模块,那么 __name__ 就是这个模块的文件名,不包含目录的路径或者文件的扩展名。>>> import humansize>>> humansize.__name__"humansize"

但是你也可以当作一个独立的程序直接运行这个模块,那样的话 __name__ 将是一个特殊的默认值 __main__。 Python 将会评估这个 if 语句,寻找一个值为 true 的表达式,然后执行这个 if 代码块。在这个例子中,打印两个值。c:homediveintopython3> c:python31python.exe humansize.py1.0 TB931.3 GiB

这就是你的第一个 Python 程序!

深入阅读#PEP 257: Docstring 约定解释了用什么来从大量的 docstring 中分辨出一个好的 docstring。

Python 参考手册解释了为什么说 Python 里面所有东西都是对象,因为有些人是书呆子,喜欢详细地讨论一些东西。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值