本章主要内容
本章介绍最基础的Python知识,包括如何使用赋值和表达式、如何输入数字或字符串、如何在代码中标明注释等。首先将介绍Python如何组织代码块,这与其他的所有主流语言都不一样。
与其他大部分编程语言不一样,Python使用空白符(whitespace)和缩进来标识代码块。也就是说,循环体、else条件从句之类的构成,都是由空白符来确定的。大部分编程语言都是使用某种大括号来标识代码块的。下面的C语言代码将会计算9的阶乘,结果保存在变量r中:
/* C语言代码 */ int n, r; n = 9; r = 1; while (n > 0) { r *= n; n--; }
这里的while循环体是用大括号包围起来的,也就是每次循环将要执行的代码。如上面的代码所示,为了能清晰地表达用途,代码一般都会多少带点缩进。但是写成以下格式也是允许的:
/* 随意缩进的C语言代码 */ int n, r; n = 9; r = 1; while (n > 0) { r *= n; n--; }
虽然以上代码非常难以阅读,但仍然可以正确运行。
下面是Python的等价实现:
# Python代码(赞!) n = 9 r = 1 while n > 0: r = r * n ⇽--- Python还支持C风格的写法r * = n n = n – 1 ⇽--- Python还支持C风格的写法n - = 1
Python不用大括号标识代码结构,而是用缩进本身来标识。上述最后两行代码就是while循环体,就是因为它们紧随while语句,并且比while语句缩进一级。如果这两行代码没做缩进,就不会构成while循环体。
采用缩进而非大括号来标识代码结构,可能需要一些时间来习惯,但却有明显的好处。
可能大家的代码已经坚持采用了缩进,所以这算不上是一大进步。如果用了IDLE,每行都会自动缩进。如果要回退缩进级别,只需要按下Backspace键即可。大多数编程用的编辑器和IDE(如Emacs、VIM和Eclipse)都提供了自动缩进功能。如果在提示符后输入命令时,前面有一个或多个空格,那么Python解释器会返回错误消息。这件事可能需要犯一两次错误才会适应。
在大多数情况下,Python文件中符号#之后的任何内容都是注释,将会被编译器忽略。有一种情况明显例外,即字符串中的#只是一个普通字符:
# 将5赋给x x = 5 x = 3 # 现在x成了3 x = "# This is not a comment"
Python代码中经常会加入注释。
赋值是最常用的Python命令,用法也与其他编程语言很类似。下面用Python代码新建变量x,并赋值为5:
x = 5
与很多其他计算机语言不同的是,Python既不需要声明变量类型,也不需要在每行代码后面添加结束符。代码换行即表示结束,变量在首次被赋值时会自动创建。
{Python中的变量:是容器(bucket)还是标签(label)?!}
在Python中“变量”这个名称或许有点儿误导性,应该叫“名称”或“标签”会更准确一些。但是,似乎所有人都习惯称为“变量”了。无论叫什么名称,都应该知道Python中的变量是如何工作的。
对变量的常见解释就是存储值的容器,有点儿像是个桶(bucket),当然这不算精确。对许多编程语言(如C语言)来说,这种解释是合理的。
但是,Python中的变量不是容器,而是指向Python对象的标签,对象位于解释器的命名空间中。任意数量的标签(或变量)可以指向同一个对象。当对象发生变化时,所有指向它的变量的值都会改变。
看过以下这段简单的代码,就能理解上述含义了:
>>> a = [1, 2, 3] >>> b = a >>> c = b >>> b[1] = 5 >>> print(a, b, c) [1, 5, 3] [1, 5, 3] [1, 5, 3]
如果将变量视为容器,以上结果就说不通了。改变了一个容器的内容,另外两个容器不应该同时发生变化。但是,如果变量只是指向对象的标签,就说得通了。3个标签都指向同一个对象,若对象发生变化,则3个标签都会反映出来。
如果变量指向的是常量或不可变值,上述区别就不是十分明显了:
>>> a = 1 >>> b = a >>> c = b >>> b = 5 >>> print(a, b, c) 1 5 1
因为变量指向的对象无法改变,所以变量的表现与两种解释均符合。实际上在第3行代码执行完毕后,a、b和c就全都指向了同一个不可更改的整数对象,其值为1。下一行代码b =5则让b指向整数对象5,但a和c的指向没有变化。
Python变量可以被设为任何对象,而在C和许多其他语言中,变量只能存储声明过的类型的值。下面的Python代码是完全合法的:
>>> x = "Hello" >>> print(x) Hello >>> x = 5 >>> print(x) 5
一开始x是指向字符串对象“Hello”的,然后又指向了整数对象5。当然,这种特性可能会遭到滥用,因为随意让同一个变量名先后指向不同的数据类型,可能会让代码变得难以理解。
新的赋值操作会覆盖之前所有的赋值,del语句则会删除变量。如果在删除变量之后设法输出该变量的内容,将会引发错误,效果就像从未创建过该变量一样:
>>> x = 5 >>> print(x) 5 >>> del x >>> print(x) Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'x' is not defined >>>
这里首先出现了跟踪信息(traceback),当检测到错误(称为异常)时就会被打印。最后一行代码显示出检测到了异常,在这里是x的NameError。在被删除之后,x不再是有效的变量名了。因为在交互模式下只输出了一行代码,所以上述示例中只返回了“line 1, in <module>”的跟踪信息。通常在错误发生时,会返回已有函数的完整动态调用层次信息。如果用了IDLE,返回的信息也是差不多的,可能会得到如下所示的代码:
Traceback (most recent call last): File "<pyshell#3>", line 1, in <module> print(x) NameError: name 'x' is not defined
第14章将会更加详细地介绍这种错误处理机制。在Python标准库文档中,列出了所有可能出现的异常及其引发原因。请使用索引来查找收到的某个异常的信息(如NameError)。
Python变量的名称是区分大小写的,可以包含字母、数字和下划线,但必须以字母或下划线开头。关于创建Python式风格的变量名称的更多内容,参见4.10节。
对于Python支持的算术表达式,多数读者都很熟悉。以下代码将会计算3和5的平均值,结果保存在变量z中:
x = 3 y = 5 z = (x + y) / 2
注意,只涉及整数的算术操作符并不一定返回整数。即便所有数值全是整数,除法运算(从Python 3开始)也会返回浮点数,所以小数部分不会被截断。如果需要传统的返回截断整数的整除,可以换用操作符//。
Python使用的是标准的算术优先规则。如果上述最后一行代码省略了圆括号,就会被计算为x +(y / 2)。
表达式不一定只是包含数值,字符串、布尔值和许多其他类型的对象都能以各种方式在表达式中使用。后面在用到时会更详细地介绍。
动手题:变量和表达式 请在Python shell中创建一些变量。在变量名中放置空格、短线或其他非字母或数字的字符,看看会发生什么?再尝试一些复杂的表达式,例如x = 2 + 4 * 5 - 6/3。用圆括号对数字进行各种不同形式的分组,看看运算结果与原来未分组时的表达式有何不同。
与其他大多数编程语言一样,Python用双引号标识字符串。以下代码将字符串“Hello, World”赋给变量x:
x ="Hello, World"
反斜杠可用于将字符转义,赋予字符特殊的含义。n表示换行符,t表示制表符,\表示反斜杠符本身。而”则是双引号本身,而不是字符串的结束符:
x = "tThis string starts with a "tab"." x = "This string contains a single backslash(\)."
可以用单引号代替双引号。以下两行代码的效果是一样的:
x = "Hello, World" x = 'Hello, World'
它们的唯一区别是:在单引号标识的字符串中,不需要对双引号字符加反斜杠;在双引号标识的字符串中,也不需要对单引号字符加反斜杠:
x = "Don't need a backslash" x = 'Can't get by without a backslash' x = "Backslash your " character!" x = 'You can leave the " alone'
普通字符串不允许跨行。以下代码将是无效的:
# 以下Python代码将引发错误——不能让1个字符串跨越2行 x = "This is a misguided attempt to put a newline into a string without using backslash-n"
但是Python支持用三重双引号标识字符串,这样字符串中不用反斜杠就能包含单引号和双引号:
x = """Starting and ending a string with triple " characters permits embedded newlines、and the use of " and ' without backslashes"""
现在x包含了两个“””之间的所有字符。可以用三重单引号‘’’来代替双引号以达到同样的效果。
Python为字符串处理提供了足够的功能,第6章将会做专题讨论。
也许大家已经对其他编程语言的标准数值操作比较熟悉了,因此本书没有用单独的章节来介绍Python的数值处理能力。本节将会介绍Python数值的独有特性,Python文档中给出了全部可用的函数。
Python提供了4种数值:整数、浮点数、复数和布尔值。整数常量就是0、-11、+33、123456之类的整数值,并且范围是无限的,大小仅受限于机器资源。浮点数可用小数点或科学计数法表示:3.14、-2E-8、2.718281828。浮点数的精度由底层硬件决定,但通常相当于C语言中的双精度(64位)类型。复数受关注的程度可能不高,本节后面将会单独讨论。布尔值是True或False,除是字符串形式之外,效果与1和0相同。
Python的算术操作与C语言很类似。两个整数的计算操作会生成一个整数,当然除法(/)除外,因为除法的结果会是浮点数。如果用了除号//,则结果会是经过截断的整数。浮点数操作则总是会返回浮点数。下面是一些例子:
>>> 5 + 2 - 3 * 2 1 >>> 5 / 2 # 普通除法将返回浮点数 2.5 >>> 5 / 2.0 # 结果还是浮点数 2.5 >>> 5 // 2 # 用'//'整除将返回截断后的整数值 2 >>> 30000000000 # 在很多编程语言中,整型是放不下的 30000000000 >>> 30000000000 * 3 90000000000 >>> 30000000000 * 3.0 90000000000.0 >>> 2.0e-8 # 科学计数法将返回浮点数 2e-08 >>> 3000000 * 3000000 9000000000000 >>> int(200.2) ⇽--- ❶ 200 >>> int(2e2) ⇽--- ❶ 200 >>> float(200) ⇽--- ❶ 200.0
这几句代码显式在多个类型间转换❶,int函数会将浮点数截断。
与C或JAVA相比,Python的数值有两个优点:整数可为任意大小,两个整数的除法结果是浮点数。
4.6.1 内置数值处理函数
Python提供了以下数值操作函数,作为其内核的一部分:
abs、divmod、float、hex、int、max、min、oct、pow、round
详情参见官方文档。
4.6.2 高级数值处理函数
Python没有内置更高级的数值处理函数,例如三角函数、双曲线三角函数,以及一些有用的常量,但它们都在标准模块math中提供,稍后将会详细介绍模块。现在只要知道,必须在Python程序或交互式会话中执行以下语句,才能使用本节的数学函数,这就足够了。
from math import *
math模块提供了以下函数和常量:
acos、asin、atan、atan2、ceil、cos、cosh、e、exp、fabs、floor、fmod、frexp、hypot、ldexp、 log、log10、mod、pi、pow、sin、sinh、sqrt、tan、tanh
{:—}详情参见官方文档。
4.6.3 数值计算
由于受限于运算速度,基本安装的Python不太适合执行密集型数值计算。但强大的Python扩展NumPy高效实现了很多高级的数值处理操作。NumPy重点实现的是数组操作,包括多维矩阵,以及快速傅里叶变换等更高级的函数。在SciPy官网中应该能够找到NumPy或其链接。
4.6.4 复数
只要表达式带有nj的形式,就会自动创建复数:n与Python的整数和浮点数形式相同,j当然就是标准的虚数表示法,等于-1的平方根。例如:
>>> (3+2j) (3+2j)
注意,当计算结果为复数时,Python会加上圆括号,表示显示的是个对象值:
>>> 3 + 2j - (4+4j) (-1-2j) >>> (1+2j) * (3+4j) (-5+10j) >>> 1j * 1j (-1+0j)
计算j * j则会如愿返回-1,但结果仍然是Python复数型对象。复数永远不会被自动转换为等价的实数或整数对象。但可以用real和imag属性轻松访问到复数的实部和虚部。
>>> z = (3+5j) >>> z.real 3.0 >>> z.imag 5.0
注意,复数的实部和虚部总是以浮点数返回。
4.6.5 高级复数函数
大多数用户都会认为,计算-1的平方根不该有结果,而是应该报错,因此math模块中的函数并不适用于复数,与其类似的复数函数是由cmath模块提供的:
acos、acosh、asin、asinh、atan、atanh、cos、cosh、e、exp、log、log10、pi、sin、sinh、sqrt、 tan、tanh
为了能在代码中清晰地标识出这些特殊用途的复数函数,避免与普通的同名函数产生冲突,最好的做法是先导入cmath模块:
import cmath
然后在用到复数函数时,显式地引用cmath包:
>>> import cmath >>> cmath.sqrt(-1) 1j
{尽量少用<module> import *!}
上述例子很好地说明了为什么应尽量减少import语句的from <module> import *的用法。如果用from形式先导入math模块,再导入cmath模块,那么cmath模块中的函数将会覆盖math模块的同名函数。对于阅读代码的人来说,也要花费更多的精力来找出某个函数的来源。有一些模块经过了明确设计,必须使用上例中的导入形式。
有关如何使用模块和模块名称的更多详细信息,参见第10章。
重点是要记住,在导入cmath模块之后,几乎就能对其他数值类型进行任何操作了。
动手题:字符串和数值操作 在Python shell中,创建一些字符串和数值型变量(整数、浮点数和复数)。体验一下操作的结果,包括跨类型的操作。例如,能否让字符串乘以整数,或者乘以浮点数或复数呢?接下来载入math模块并测试一些函数,然后载入cmath模块并执行同名函数。当载入cmath模块后,对整数或浮点数调用其中的函数,会产生什么结果?怎样才能让math模块的函数重新可用呢?
除字符串、数值等标准类型之外,Python还有一种特殊的基本数据类型,它定义了名为None的特殊数据对象。顾名思义,None用于表示空值。在Python中,None会以各种方式存在。例如,Python中的“过程”,只是一个没有显式返回值的函数,这表示默认返回的是None。
在日常的Python编程中,None经常被用作占位符,用于指示数据结构中某个位置的数据将会是有意义的,即便该数据尚未被计算出来。检测None是否存在十分简单,因为在整个Python系统中只有1个None的实例,所有对None的引用都指向同一个对象,None只等价于它自身。
利用input()函数可以获取用户的输入。input()函数可以带一个字符串参数,作为显示给用户的提示信息:
>>> name = input("Name? ") Name? Jane >>> print(name) Jane >>> age = int(input("Age? ")) ⇽--- 将输入的字符串转换为整数 Age? 28 >>> print(age) 28 >>>
这种获取用户输入的方法相当简单。用户输入是以字符串的形式获得的,所以要想用作数字,必须用int()或float()函数进行转换。这算得上是个小陷阱吧。
动手题:获取用户输入 体验一下用input()函数读取用户输入的字符串和整数。代码与上述例子类似,如果读取整数时没有在input()外面调用int(),那会出现什么效果?能否修改一下代码,读取一个浮点数(如28.5)?如果故意输入“错误”的数据类型会怎么样?例如,本该是整数的地方输入了浮点数,本该是数字的地方输入了字符串,反之又会如何?
Python提供了多种内置操作符,标准的操作符有+、*等,更高级的有移位、按位逻辑运算函数等。大多数操作符都不是Python独有的,其他的编程语言也提供,因此本书不再做解释。Python内置操作符的完整列表,可在官方文档中找到。
除明确要求用缩进来标识代码块之外,Python对编码风格的限制相对较少。即便如此,缩进量和缩进类型(制表符与空格)也没做强制性规定。不过在“Python 增强提案 8”(Python Enhancement Proposal 8,PEP 8)中,包含了推荐的编码风格规范。本书附录A有对PEP 8的概括性介绍,全文可在Python官方网站在线获取。表4-1中列出了部分Python式风格的规范,但为了能完全理解Python式风格,还请反复阅读PEP 8。
强烈建议遵循PEP 8规范。因为每条规范都是精心挑选过的,并经过了时间考验,能让代码更容易被Python程序员理解。
速测题:Python风格 请在以下变量名和函数名中,选出不大符合Python风格的名称,并说明理由:bar(、varName、VERYLONGVARNAME、foobar、longvarname、foo_bar()、really_very_long_var_name。
本文摘自《Python 快速入门》第3版
这是一本Python快速入门书,基于Python 3.6编写。本书分为4部分,第一部分讲解Python的基础知识,对Python进行概要的介绍;第二部分介绍Python编程的重点,涉及列表、元组、集合、字符串、字典、流程控制、函数、模块和作用域、文件系统、异常等内容;第三部分阐释Python的特性,涉及类和面向对象、正则表达式、数据类型即对象、包、Python库等内容;第四部分关注数据处理,涉及数据文件的处理、网络数据、数据的保存和数据探索,最后给出了相关的案例。
本书框架结构清晰,内容编排合理,讲解循序渐进,并结合大量示例和习题,让读者可以快速学习和掌握Python,既适合Python初学者学习,也适合作为专业程序员的简明Python参考书。