一、Python3初识
1、创建并运行Python程序
要编写Python程序,可以使用任意能加载与保存文本的普通文本编辑器。默认情况下,Python文件使用UTF-8字符编码,UTF-8是ASCII的超集,可以完全表达每种语言中的所有字符。通常,Python文件的扩展名为.py,不过,在一些UNIX类系统上(比如Linux与Mac OS X),有些Python应用程序没有扩展名,Python GUI(图形用户界面)程序的扩展名则为.pyw(特别是在Windows与Mac OS X 上)。
2、第一个Python程序
在学习一门语言的开始,通常我们都会创建一个打印hello world的程序,Python也不例外。在普通的文本编辑器中创建一个名为hello.py的程序,其中包含以下内容:
#!/usr/bin/python3
#encoding: utf-8
print("Hello","World!")
第1和2行为注释。在Python中,注释以#开始,作用范围为该行。
在 UNIX上,当某程序在控制器台被引用时,该文件的头两个字节先被读入。如果这两个字节是ASCII字节#!,shell就会认为该文件将要由解释器执行,并且该文件的首行指定了要使用哪个解释器。该行称为 shebang(shell执行)行,如果存在,就必须为可执行文件的首行。
shebang 行通常呈现为如下两种形式之一:
#!/usr/bin/python3 或 #!/usr/bin/env python3
如果是第一种形式,就会使用指定的解释器。这种形式对将由Web服务器运行的Python程序是必要的,尽管指定的路径可能与这里给出的不同。如果是第二种形式,就会使用在 shell 当前环境中发现的第一个 pythons 解释器。第二种形式具有更强的适应性,因为这种情况考虑了 Python3解释器位于 /usr/bin 之外的可能性。
需要注意的是,对于UNIX系统,我们假定在PATH路径下,Python3的可执行程序名(或到改名的软连接)是Python3。如果不是这种情况,就需要改变实例中的 shebang 行,以便使用正确的程序名(如果使用的是第一种形式,就需要正确的名称与路径)。
第二行是编码格式。
第三行为空行,Python会忽略空行,但空行通常有助于将大块代码分割,以便于阅读。
第四行为Python代码,其中调用了print()函数,该函数带2个参数,每个参数的类型都是str(字符串,即一个字符序列)。
3、Python语法介绍
.py文件中的每个语句都是顺序执行的,从第一条语句开始,逐行执行。这与其他一些语言是不同的。
4、执行Python程序
在终端输入如下指令(假定代码保存在Home的python文件夹下):
$ cd /Home/python
$ python3 hello.py
# 输出结果:Hello World!
二、Python的8个关键要素
1、要素#1:数据类型
Python提供了几种内置的数据类型,现在我们只关注其中的两种。Python使用int类型表示整数(正或负整数),使用str类型表示字符串(Unicode字符序列)。
另外,Python所能表示的整数大小只受限于机器内存,而非固定数量的字节数。字符串可以使用双引号或单引号封装--只要字符串头尾使用的符号是对称的。空字符串则只是使用引号,中间没有任何内容。
Python使用方括号([])来存取字符串等序列中的某一项。方括号存取这种语法适用于任意数据类型(只要构成一个序列)的数据项,比如字符串或列表。需要注意的是,Python语法中,索引位置也是从0开始计数的。例如,在下面代码中取出第5个字符:
print("HelloWorld!"[5])
# 输出结果: W
在Python中,str类型与基本的数值类型(比如 int)都是固定的。也就是说,一旦设定,其值就不能改变。也就是说,虽然可以使用方括号取出字符串中某给定索引位置处的字符,但是,不能将其设置为新字符(注意,在Python中,字符就是指长度为1的字符串)。
2、要素#2:对象引用
定义了数据类型之后,接下来要做的事情就是定义存储某种类型数据的变量,但Python没有这样的变量,而是使用“对象引用”。对固定对象而言,变量与对象引用之间没有可察觉的差别。对于可变对象,则存在差别,但是在实际工作中很少有影响。例如:
x = "Hello"
这里不需要预先的声明语句,也没有必要指定值的类型。语法就是简单的 objectReference = value。在执行上述语句的时候,Python会创建一个str对象,其文本内容为"Hello",同时还创建了一个名为x的对象引用,x引用的就是这个str对象。如果修改了x的值,且不存在更多的对字符串"Hello"的对象引用,则Python可以对其进行垃圾收集处理。
注意:用于对象引用的名称(称为“标识符”)有一些限制,尤其是不能与任何Python关键字相同,并且必须以字母或下划线引导,其后跟随0个或多个非空字符、下划线或数字。标识符没有长度限制,字母与数字指的是Unicode编码中所定义的,也就是说,包含但不限于ASIIC编码定义的字母与数字("a"、"b"、...、"z"、"A"、"B"、...、"Z"、"0"、...、"9")。此外,Python标识符是大小写敏感的,因此,index、Index与INDEX是3个不同的标识符。
Python使用“动态类型”机制,也就是说,在任何时刻,只要需要,某个对象引用都可以重新引用一个不同的对象(可以是不同的数据类型)。
3、要素#3:组合数据类型
Python提供了几种组合数据类型,包括关联数组与集合等类型。在这里,我们讨论一下元组与列表。Python元组与列表可用于存储任意数量、任意类型的数据项。
3.1 元组
元组是固定的,创建之后就不能改变;列表是可变的,在需要的时候,可以插入或移除数据项。例如:
"Lily","Zhangsan","Lisi"
("Lily","Zhangsan","Lisi")
元组使用逗号创建,在输出时,Python使用圆括号将其封装在一起。如果某个元组只有一个数据项,又需要使用圆括号,就仍然必须使用逗号,例如:
"Lisa",
("Lisa",)
空数组使用空的 () 创建,逗号还可以用于在函数调用时分隔参数,因此,如果需要将元组常值作为参数传递,就必须使用括号对其进行封装,以免混淆。
3.2 列表
列表可以使用方括号 [] 创建,例如:
[1,4,5,7,2]
['A','B','C','D','E']
['zhangsan',20,'kuhe',200]
[] #空列表
空列表使用空的 [] 创建。
3.3 元组和列表的共同点
实质上,元组与列表并不是真正的存储数据项,而是存放对象引用。创建列表与元组时(以及在列表中插入数据项时),实际上是使用其给定的对象引用的副本。在字面意义项(比如整数或字符串)的情况下,会在内存中创建适当数据类型的对象,而存放在列表或元组中的才是对象引用。
组合数据类型也是对象,因此,可以将某种组合数据类型嵌套在其他组合数据类型中,比如,创建一个其中每个元素都是列表的列表。
3.4 列表list的增删查改
增加:append(),例如:
1、x = ['zhangsan',30,-89,'A',200]
x.append('more')
print(x)
# 输出结果:['zhangsan',30,-89,'A',200,'more']
2、list.append(x,'extra')
print(x)
['zhangsan',30,-89,'A',200,'more','extra']
插入:insert(),该方法用于在某特定的索引位置插入数据项;
删除:remove(),该方法用于移除某给定索引位置上的数据项;
查找:使用放括号操作符从列表中获取某个位置的值。例如:
x = ['zhangsan',30,-89,'A',200]
print(x[0]) # 输出结果:zhangsan
print(x[3]) # 输出结果:A
修改:列表是可变的,使用[]操作符设置列表元素,例如:
x = ['zhangsan',30,-89,'A',200]
x[1] = "hello"
print(x)
# 输出结果:['hello',30,-89,'A',200]
3.5 列表与元组的区别
列表是可变的,元组是固定的。
4、要素#4:逻辑操作符
Python提供了4组逻辑运算。
4.1 身份操作符
身份操作符的作用是查看两个对象引用是否指向相同的对象,或查看某个对象是否为None。如果我们需要比较对象值,就应该使用比较操作符。
由于所有的Python变量实际上都是对象引用,有时,询问两个或更多的对象引用是否都指向相同的对象是有意义的。is 操作符是一个二元操作符,如果其左端的对象引用与右端的对象引用指向的是同一个对象,则会返回true。例如:
a = [20,'A',None]
b = [20,'A',None]
print(a is b)
# 输出结果: False
b = a
print(a is b)
# 输出结果: True
注意:虽然 a 和 b 在最初设置为相同的列表值,但是列表本身是以单独的 list 对象存储的,因此,在第一次输出时,is 操作符的返回 false。
身份比较的一个好处是速度非常快,这是因为,并不必须对进行比较的对象本身进行检查,is 操作符只需要对对象所在的内存地址进行比较--同样的地址存储的是同样的对象。
最常见的使用 is 的情况是将数据项与内置的空对象 None 进行比较,None通常用作位置标记值,指示“未知”或“不存在”,使用 is not 是对身份测试的反向测试。例如:
a = "Anything"
b = None
print(a is not None,b is None)
# 输出结果:(True,True)
4.2 比较操作符
< 表示小于,<= 表示小于或等于,== 表示等于,!= 表示不等于,>= 表示大于或等于,> 表示大于,例如:
a = 2
b = 6
print(a==b) # 输出结果 False
print(a<b) # 输出结果 True
print(a<=b,a!=b,a>=b,a>b)
# 输出结果 (True, True, False, False)
对于整数的比较结果与我们期待的结果是一样的。同样,对于字符串进行比较操作,也可以获得正确的结果:
a = "Anything"
b = "Anything"
print(a is b) # 输出结果:False
print(a == b) # 输出结果:True
从实例可以看出,虽然 a 与 b 是不同的对象(有不同的身份),但是具有相同的值,因此比较的结果是相等的。
Python 比较操作符的一个特别好用的特性是可以进行结链比较,例如:
a = 9
print(0 <= a <= 10) # 输出结果:True
对于给定数据项取值在某个范围内的情况,这种测试方式提供了很多便利,不再需要使用逻辑运算符 and 进行两次单独的比较操作(大多数其他语言都需要如此)。这种方式的另一个附加的好处是只需要对数据项进行一次评估(因为数据项在表达式中只出现一次),如果数据项的计算需要耗费大量时间或存取数据项会带来一些副作用,这种优势就会更加明显。
4.3 成员操作符
对序列或集合这一类数据类型,比如字符串、列表或元组,我们可以使用操作符 in 来测试成员关系,用 not in 来测试非成员关系。例如:
p = (8,'X',10,-7,0,3)
print(3 in p) # 输出结果:True
print('A' not in p) # 输出结果:True
对列表与元组,in 操作符使用线性搜索,对非常大的组合类型(包含数万个或更多的数据项),速度可能会较慢;而对字典或集合,in 操作可以非常快。下面是 in 操作符对字符串进行相关操作:
word = "Hello World"
print("H" in word) # 输出结果:True
print("llo" in word) # 输出结果:True
对于字符串数据类型,使用成员运算符可以很方便地测试任意长度的子字符串。
4.4 逻辑运算符
Python提供了3个逻辑运算符:and、or 与 not。and 与 or 都使用 short-circuit 逻辑,并返回决定结果的操作数--而不是返回布尔值(除非实际上就是布尔操作数)。例如:
five = 5
two = 2
zero = 0
print(five and two) #输出结果:2
print(two and five) #输出结果:5
print(five and zero) #输出结果:0
如果逻辑表达式本身出现在布尔上下文中,那么结果也为布尔值,因此,前面的表达式结果将变为True、True 与 False,比如,if语句。
nought=0
five or two # 结果:5
two or five # 结果:2
zero or five # 结果:5
zero or nought # 结果:0
or操作符是类似的,这里,在布尔上下文中,结果应该为True、True、True与False。
not 单一操作符在布尔上下文中评估其参数,并总是返回布尔型结果,对前面的实例,not(zero or nought)的结果为True,not two 的结果为 False。
5、要素#5:控制流语句
布尔表达式实际上就是对某对象进行布尔运算,并产生一个布尔值结果(True或False)。在Python中,预定义为常量False的布尔表达式、特殊对象None、空序列或集合(比如,空字符串、列表或元组)、值为0的数值型数据项等的布尔结果为False,其他的则为True。创建自定义数据类型时,我们可以自己决定这些自定义数据类型在布尔上下午文中的返回值。
在Python中,一块代码,也就是说一条或多条语句组成的序列,称为suite。由于Python中的某些语法要求存在一个suite,Python就提供了关键字pass,pass实际上是一条空语句,不进行任何操作,可以用在需要suite(或者需要指明我们已经考虑了特殊情况),但又不需要进行处理的地方。
5.1 if语句
Python的常规 if 语句语法如下:
if bool_expression1:
suite1
elif bool_expression2:
suite2
...
elif bool_expressionN:
suiteN
else:
else_suite
与if语句对应的可以有0个或多个elif分支,最后的else分支是可选的。如果需要考虑某个特定的情况,但又不需要在这种情况发生时进行处理,那么可以使用pass作为该分支的suite。
与大多数其他程序设计语言不同的是,Python使用缩排来标识其块结构。
由于suite是使用缩排指明的,因此很自然地带来一个问题是:使用哪种缩排?Python风格指南建议的是每层缩排4个空格,并且只有空格(没有制表符)。
5.2 while语句
while语句用于0次或多次执行某个suite,循环执行的次数取决于while循环中布尔表达式的状态。下面给出语法格式:
while bool_expression:
suite
实际上,while循环的完整语法比上面的要复杂得多,这是因为在其中可以支持break与continue,还包括可选的 else 分支。break 语句的作用是将控制流导向到 break 所在的最内层循环--也就是说跳出循环;continue 语句的作用是将控制流导向到循环起始处。通常,break 语句与 continue 语句都用在 if 语句内部,以便条件性地改变某个循环的执行流程。例如:
while True:
item = get_next_item()
if not item:
break
process_item(item)
while循环具有非常典型的结构,只要还存在需要处理的数据项,就一直循环(get_next_item() 与 process_item()都是在某处定义的自定义函数)。在上面的实例中,while 语句的 suite 中包含了一条 if 语句,该 if 语句本身又包含了自己的 suite,因此,此例中必须包含一条 break 语句。
5.3 for...in 语句
语法格式:
for variable in iterable:
suite
5.4 基本的异常处理
与Python的其他对象一样,异常也是一个对象,转换为字符串时(比如,打印时),异常会产生一条消息文本。异常处理的简单语法格式如下:
try:
try_suite
except exception1 as variable1:
exception_suite1
...
except exceptionN as variableN:
exception_suiteN
注意:as variable 部分是可选的。我们可以只关心产生了某个特定的异常,而不关心其具体的消息文本。
异常处理的工作逻辑:
如果 try 块中的 suite 都正常执行,而没有产生异常,则 except 模块将被跳过;如果 try 块中产生了异常,则控制流会立即转向第一个与该异常匹配的 suite --- 这意味着,跟随在产生异常的语句后面的 suite 中的语句将不再执行;如果发生了异常,并且给定了 as variable 部分,则在异常处理 suite 内部,variable 引用的是异常对象。
如果异常发生在处理 except 块时,或者某个异常不能与任何一个 except 块匹配,Python 就会在下一个封闭范围内搜索一个匹配的 except 块。对合适的异常处理模块的搜索是向外扩展的,并可以延伸到调用栈内,直到发现一个匹配的异常处理模块,或者找不到匹配的模块,这种情况下,程序将终止,并留下一个未处理的异常,此时,Python会打印回溯信息以及异常的消息文本。
s = input("enter an integer:")
try:
i = int(s)
print("valid integer entered:",i)
except ValueError as err:
print(err)
# 如果用户输入的是 3.5,那么输出为:invalid literal for int() with base 10:'3.5'
# 但是如果用户输入的是 13,那么输出为:valid integer entered: 13
6、要素#6:算数操作符
Python提供了完整的算数运算符集,包括用于基本四则数学运算的操作符+、-、*、/。增强的赋值运算符,比如,+=与*=。
注意:在Python中,-号既可以作为单值操作符(否定),也可以作为二元操作符(减法),Python与一般程序语言不同的地方在于对除法的处理:除法操作符会产生一个浮点值,而不是一个整数值。如果需要产生一个整数值结果,我们可以使用int()进行转换。例如:
print(12/3) # 输出结果:4.0
7、要素#7:输入/输出
Python提供了内置的 intput() 函数,用于接收来自用户的输入,print()函数,展示输出的内容。这一函数需要一个可选的字符串参数(并将其在控制台上打印),之后等待用户输入响应信息或按Enter键(或Return键)来终止。如果用户不输入任何文本,而只是按 Enter 键,那么 input() 函数会返回一个空字符串;否则,会返回一个包含了用户输入内容的字符串,而没有任何行终止符。8、要素#8:函数的创建与调用
Python提供了一种将多个 suites 封装为函数的途径,函数就可以参数化,并 通过传递不同的参数来调用。下面给出的是用于创建函数的通用语法格式:
def functionName(arguments):
suite
这里,argument是可选的,如果有多个参数,就必须使用逗号进行分隔。每个Python函数有一个返回值,默认情况下为None,除非我们使用语法 return value 来函数返回,此时 value 是实际的返回值。返回值可以是仅仅一个值,也可以是一组值。调用者可以忽略返回值。
注意,def 是一条与赋值操作符工作方式类似的语句。执行def时,会创建一个函数对象,同时创建一个带有指定名的对象引用(引用该函数对象)。由于函数也是对象,因此可以存储在组合数据类型中,并作为参数传递给其他函数。
下面是一个频繁的从用户获取整数的实例函数:
def get_int(msg):
while True:
try:
i = int(input(msg))
return i
except ValueError as err:
print(err)
# 调用:
age = get_int("enter your age:")
这个函数有一个参数 msg,在while循环内部,用户被要求输入一个整数,如果输入无效,则会产生一个 ValueError异常,并打印错误消息,同时循环也将迭代进行。输入有效的整数后,会返回给调用者。
Python模块实际上就是包含Python代码的.py文件,比如自定义函数与类(自定义数据类型)的定义,有时候还包括变量等。要使用某个模块内的函数功能,必须先导入该模块,例如:
import sys
# 访问其内部的变量
print(sys.argv)
要导入一个模块,必须使用 import 语句,其后跟随 .py 文件名,但是不需要写出该扩展名。导入一个模块后,就可以访问其内部包含的任意函数、类以及变量。通常,使用模块中的函数的语法格式为 moduleName.functionName(arguments)。
常规的做法是将所有 import 语句放在 .py 文件的起始处,在 shebang 行和模块的文档之后。建议首先导入标准库模块,之后导入第三方模块,最后才导入自己编写的模块。