布尔表达式与其余值的替换
值的测试
Python不仅仅可以使用布尔型变量作为条件,它可以直接在if
中使用任何表达式作为条件:
大部分表达式的值都会被当作True
,但以下表达式值会被当作False
:
- False
- None
- 0
- 空字符串,空列表,空字典,空集合
循环
else语句
与 if
一样, while
和 for
循环后面也可以跟着 else
语句,不过要和break
一起连用。
- 当循环正常结束时,循环条件不满足,
else
被执行; - 当循环被
break
结束时,循环条件仍然满足,else
不执行。
values = [7, 6, 4, 7, 19, 2, 1]
for x in values:
if x <= 10:
print 'Found:', x
break
else:
print 'All values greater than 10'
xrange函数
total = 0
for i in range(100000):
total += i
print total
4999950000
然而这种写法有一个缺点:在循环前,它会生成一个长度为 100000
的临时列表。
生成列表的问题在于,会有一定的时间和内存消耗,当数字从 100000
变得更大时,时间和内存的消耗会更加明显。
为了解决这个问题,我们可以使用 xrange
来代替 range
函数,其效果与range
函数相同,但是 xrange
并不会一次性的产生所有的数据:
total = 0
for i in xrange(100000):
total += i
print total
4999950000
列表推导式
values = [10, 21, 4, 7, 12]
squares = [x**2 for x in values]
print squares
[100, 441, 16, 49, 144]
还可以在列表推导式中加入条件进行筛选。 例如在上面的例子中,假如只想保留列表中不大于10
的数的平方:
values = [10, 21, 4, 7, 12]
squares = [x**2 for x in values if x <= 10]
print squares
[100, 16, 49]
也可以使用推导式生成集合和字典:
square_set = {x**2 for x in values if x <= 10}
print(square_set)
square_dict = {x: x**2 for x in values if x <= 10}
print(square_dict)
set([16, 49, 100])
{10: 100, 4: 16, 7: 49}
再如,计算上面例子中生成的列表中所有元素的和:
total = sum([x**2 for x in values if x <= 10])
print(total)
165
但是,Python会生成这个列表,然后在将它放到垃圾回收机制中(因为没有变量指向它),这毫无疑问是种浪费。
为了解决这种问题,与xrange()类似,Python使用产生式表达式来解决这个问题:
total = sum(x**2 for x in values if x <= 10)
print(total)
165
与上面相比,只是去掉了括号,但这里并不会一次性的生成这个列表。
函数
接收不定参数
def add(x, *args):
total = x
for arg in args:
total += arg
return total
这里,*args
表示参数数目不定,可以看成一个元组,把第一个参数后面的参数当作元组中的元素。
这样定义的函数不能使用关键词传入参数,要使用关键词,可以这样:
def add(x, **kwargs):
total = x
for arg, value in kwargs.items():
print "adding ", arg
total += value
return total
这里, ** kwargs 表示参数数目不定,相当于一个字典,关键词和值对应于键值对。
print add(10, y=11, z=12, w=13)
adding y
adding z
adding w
46
再看这个例子,可以接收任意数目的位置参数和键值对参数:
def foo(*args, **kwargs):
print args, kwargs
foo(2, 3, x='bar', z=10)
(2, 3) {'x': 'bar', 'z': 10}
不过要按顺序传入参数,先传入位置参数 args
,在传入关键词参数 kwargs
。
返回多个值
函数可以返回多个值:
事实上,Python将返回的两个值变成了元组:
print to_polar(3, 4)
(5.0, 0.9272952180016122)
因为这个元组中有两个值,所以可以给两个值赋值。
列表也有相似的功能:
a, b, c = [1, 2, 3]
print a, b, c
1 2 3
事实上,不仅仅返回值可以用元组表示,也可以将参数用元组以这种方式传入:
def add(x, y):
"""Add two numbers"""
a = x + y
return a
z = (2, 3)
print add(*z)
5
这里的*
必不可少。
还可以通过字典传入参数来执行函数:
def add(x, y):
"""Add two numbers"""
a = x + y
return a
w = {'x': 2, 'y': 3}
print add(**w)
5
map 方法生成序列
可以通过 map
的方式利用函数来生成序列:
def sqr(x):
return x ** 2
a = [2,3,4]
print map(sqr, a)
[4, 9, 16]
其用法为:
map(aFun, aSeq)
将函数 aFun
应用到序列 aSeq
上的每一个元素上,返回一个列表,不管这个序列原来是什么类型。
事实上,根据函数参数的多少,map
可以接受多组序列,将其对应的元素作为参数传入函数:
def add(x, y):
return x + y
a = (2,3,4)
b = [10,5,3]
print map(add,a,b)
[12, 8, 7]
模块和包
在导入时,Python会执行一遍模块中的所有内容。
ex1.py
中所有的变量都被载入了当前环境中,不过要使用
ex1.变量名 的方法来查看或者修改这些变量
ex1.函数名 调用模块里面的函数:
为了提高效率,Python只会载入模块一次,已经载入的模块再次载入时,Python并不会真正执行载入操作,哪怕模块的内容已经改变。 需要重新导入模块时,可以使用reload
强制重新载入它
_name__
属性
有时候我们想将一个 .py
文件既当作脚本,又能当作模块用,这个时候可以使用 __name__
这个属性。
只有当文件被当作脚本执行的时候, __name__
的值才会是 '__main__'
,所以我们可以:
%%writefile ex2.y
PI = 3.1416
def test():
w = [0,1,2,3]
print 'test passed.'
if __name__ == '__main__':
test()
包
假设我们有这样的一个文件夹:
foo/
__init__.py
bar.py
(defines func)baz.py
(defines zap)
这意味着 foo 是一个包,我们可以这样导入其中的内容:
from foo.bar import func
from foo.baz import zap
bar
和 baz
都是 foo
文件夹下的 .py
文件。
导入包要求:
- 文件夹
foo
在Python的搜索路径中 __init__.py
表示foo
是一个包,它可以是个空文件。
异常
try & except 块
一旦 try
块中的内容出现了异常,那么 try
块后面的内容会被忽略,Python会寻找 except
里面有没有对应的内容,如果找到,就执行对应的块,没有则抛出这个异常。
如:try
抛出的是 ValueError
,except
中有对应的内容,所以这个异常被 except
捕捉到,程序可以继续执行
finally
try/catch 块还有一个可选的关键词 finally。
不管 try 块有没有异常, finally 块的内容总是会被执行,而且会在抛出异常前执行,因此可以用来作为安全保证,比如确保打开的文件被关闭
在抛出异常前执行, 如果异常被捕获了,在最后执行。
文件读写
写入测试文件:
%%writefile test.txt
this is a test fileS.
hello world!
python is good!
today is a good day.
Writing test.txt
读文件
使用 open
函数或者 file
函数来读文件,使用文件名的字符串作为输入参数:这两种方式没有太大区别。
f = open('test.txt')
f = file('test.txt')
默认以读的方式打开文件,如果文件不存在会报错。
可以使用 read
方法来读入文件中的所有内容:
text = f.read()
print text
this is a test file.
hello world!
python is good!
today is a good day.
也可以按照行读入内容,readlines
方法返回一个列表,每个元素代表文件中每一行的内容:
f = open('test.txt')
lines = f.readlines()
print lines
['this is a test file.
', 'hello world!
', 'python is good!
', 'today is a good day.']
使用完文件之后,需要将文件关闭。
f.close()
事实上,我们可以将 f
放在一个循环中,得到它每一行的内容:
写文件
我们使用 open
函数的写入模式来写文件:
f = open('myfile.txt', 'w')
f.write('hello world!')
f.close()
使用 w
模式时,如果文件不存在会被创建,我们可以查看是否真的写入成功:
如果文件已经存在, w
模式会覆盖之前写的所有内容:
除了写入模式,还有追加模式 a
,追加模式不会覆盖之前已经写入的内容,而是在之后继续写入:
写入结束之后一定要将文件关闭,否则可能出现内容没有完全写入文件中的情况。
还可以使用读写模式 w+
:
f = open('myfile.txt', 'w+')
f.write('hello world!')
f.seek(6)
print f.read()
f.close()
world!
二进制文件
二进制读写模式 b:
import os
f = open('binary.bin', 'wb')
f.write(os.urandom(16))
f.close()
f = open('binary.bin', 'rb')
print repr(f.read())
f.close()
'x86Hx93xe1xd8xefxc0xaa(x17xa9xc9xa51xf1x98'
换行符
不同操作系统的换行符可能不同:
使用 U
选项,可以将这三个统一看成
换行符。
关闭文件
在Python中,如果一个打开的文件不再被其他变量引用时,它会自动关闭这个文件。
所以正常情况下,如果一个文件正常被关闭了,忘记调用文件的 close
方法不会有什么问题。
关闭文件可以保证内容已经被写入文件,而不关闭可能会出现意想不到的结果:
with 方法
Python提供了更安全的方法,当 with
块的内容结束后,Python会自动调用它的close
方法,确保读写的安全:
with open('newfile.txt','w') as f:
for i in range(3000):
x = 1.0 / (i - 1000)
f.write('hello world: ' + str(i) + '
')
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
<ipython-input-24-9d2a70065b27> in <module>()
1 with open('newfile.txt','w') as f:
2 for i in range(3000):
----> 3 x = 1.0 / (i - 1000)
4 f.write('hello world: ' + str(i) + '
')
ZeroDivisionError: float division by zero
与 try/exception/finally
效果相同,但更简单。