5.1 print和import的更多使用方式
5.1.1 使用逗号输出
print 'Age',42 print 1,2,3
如果要同时输出文本和变量值,又不希望使用字符串格式化的话,那么这个特性就比较有用了
>>> name = 'Gumby' >>> salutation = 'Mr.' >>> greeting = 'Hello' >>> print greeting,salutation,name Hello Mr. Gumby >>> print greeting + ',',salutation,name Hello, Mr. Gumby >>> print greeting,',',salutation,name Hello , Mr. Gumby
5.1.2 把某件事作为另一件事导入
导入模块的方法:以下四种
import somemodule from somemodule import somefunction from somemodule import somefunction1 somefunction2 somefunction3 from somemodule import *
另一种方式,为模块提供别名
>>> import math as foobar >>> print foobar.sqrt(9) 3.0
或者为函数提供别名
>>> from math import sqrt as foobar >>> foobar(4) 2.0
5.2 赋值魔法
就算是不起眼的赋值豫剧也有一些特殊的技巧
5.2.1 序列解包
多个赋值操作同时进行:
>>> x,y,z = 1,2,3 >>> print x,y,z 1 2 3
交换变量:
>>> y=x >>> print x,y,z 1 1 3 >>> x,z=z,x >>> print x,y,z 3 1 1
上面的操作过程叫做序列解包或递归解包
当函数或者方法返回元组(或者其他序列或可迭代对象)时,这个特性比较有用。假设需要获取(和删除)字典中的任意的键-值对,可以使用popitem方法,这个方法将键值作为元组返回,那么这个元组就可以直接赋值到两个变量中。
>>> dd = {'name':'Anti','Age':42} >>> key,value = dd.popitem() >>> key 'Age' >>> value 42
5.2.2 链式赋值
链式赋值是将同一个值赋给多个变量的捷径。它看起来有些像并行赋值
示例如下:
x = y = somefunction() # y = somefunction() x = y
另一个:
x = somefunction()
y = somefunction()
上面的两种表达式起到的效果是不一样的
5.2.3 增量赋值
>>> x = 2 >>> x += 1 #加等 >>> x 3 >>> x *= 6 #乘等 >>> x 18 >>> x -= 2 #减等 >>> x 16
增量赋值让代码更加紧凑和简练易读
5.3 语句块
在python中,冒号(:)用来标识语句块的开始,块中的每一个语句都是缩进的(缩进量相同)
5.4 条件和条件语句
5.4.1 布尔变量的作用
真值,也叫作布尔值,有Ture和False两种
False的几种形式:None,False,0,(空),(),[],{}
bool函数用来(和list,str以及tuple一样)转换其他值
>>> bool('I think, therefor I am.') True >>> bool([]) False >>> bool({'name':'Aoto'}) True >>> bool(0) False
5.4.2 条件执行和if语句
if语句可以用来实现条件执行
5.4.3 else子句
name = raw_input("What's your name ? ") if name.endswith('Gumby'): print 'Hello, Mr.Gumby.' else: print 'Hello, stranger.' #输出如下 What's your name ? Gumby Hello, Mr.Gumby.
5.4.4 elif语句
if ...: do ... elif ...: do ... else: do ...
5.4.5 嵌套代码块
if语句中嵌套使用if语句
5.4.6 更复杂的条件
1.比较运算符
常见的如下:
x == y:x等于y
x < y:x小于y
x > y:x大于y
x >= y:x大于等于y
x <= y:x小于等于y
x != y:x不等于y
x is y:x和y是同一对象
x is not y:x和y不是同一对象
x in y:x是y的容器(如:序列)的成员
x not in y:x不是y的容器(如:序列)的成员
只有当x和y是相同或相近类型的对象时,比较才有意义
在python3中,比较不兼容的两个对象已经不再可行
2.相等运算符:==
单个相等运算符是赋值运算符,是用来改变值得,而不是用来比较
3.is:同一性运算符
>>> x = y = [1,2,3] >>> z = [1,2,3] >>> x == y True >>> x == z True >>> x is y True >>> x is z False #注意
因为is运算符是判定同一性而不是相等性的。x和y都被绑定在同一个列表上,而变量z被绑定在另一具有相同数值和顺序的列表上。它们的值可能相同,但却不是同一个对象
总结:使用(==)运算符来判定两个对象是否相等,使用is判定两者是否相同
4.in:成员资格运算符
5.字符串和序列比较
6.布尔运算符
number = input('Enter a number between 1 and 10 : ') if number <= 10 and number > 1: print 'Great!' else: print 'Wrong!' #输出如下 Enter a number between 1 and 10 : 8 Great!
and运算符在两者都为真时返回真,否则返回假,与and类似的还有or(或)和not(否)
用处:
name = raw_input('Please input your name: ') or '<Unknow>' print name #输出如下: Please input your name: <Unknow> #输出如下: Please input your name: Aoto Aoto
三元运算符:
a if b else c
如果b为真,返回a,否则返回c
x=2 if 10>=2 else 4 print x result = 'gt' if 1 >3 else 'lt' print result
5.4.7 断言:assert
if not condition: crash program
什么时候需要这样的代码?
就是因为与其让程序与其在晚些时候崩溃,不如在错误条件出现时直接让他崩溃。一般来说,你可以要求某些条件必须为真。语句中使用的关键字是assert
>>> age = 10 >>> assert 0 < age < 100 >>> age = -1 >>> assert 0 < age < 100 Traceback (most recent call last): File "<stdin>", line 1, in <module> AssertionError
如果需要确保程序中的某一个条件一定为真才能让程序正常工作的话,assert语句就有用了,他可以在程序中植入检查点
条件之后可以添加字符串,用来解释断言
>>> age = -1 >>> assert 0 < age < 100, 'The age must be reallistic.' Traceback (most recent call last): File "<stdin>", line 1, in <module> AssertionError: The age must be reallistic.
5.5 循环
5.5.1 while循环
name = '' while not name or name.isspace(): name = raw_input('Please enter your name: ') print 'Hello,%s!' % name #输出如下: Please enter your name: Please enter your name: #输入空格是无效的,要求重新输入 Please enter your name: dodo Hello,dodo!
5.5.2 for循环
kl = [] for i in range(1,10,2): kl.append(i) print kl #输出如下 [1, 3, 5, 7, 9]
提示:如果能使用for循环,就尽量不要使用while循环
range与xrange:
xrange函数的循环类似于range函数,区别爱与range函数一次性创建整个序列,而xrange一次只创建一个数。当需要迭代一个巨大的序列时xrange会更高效,不过一般情况下还是用range即可。
5.5.3 循环遍历字典元素
>>> d = {'name':'ToTo','Age':23,'Address':'BeiJing'} >>> for key in d: ... print key,'corresponds to',d[key] ... Age corresponds to 23 name corresponds to ToTo Address corresponds to BeiJing >>> for k,v in d.items(): ... print k,'corresponds to',v ... Age corresponds to 23 name corresponds to ToTo Address corresponds to BeiJing
5.5.4 一些迭代工具
1.并行迭代
names = ['Anne','Beth','George','Damon'] ages = [12,23,78,67] for name,age in zip(names,ages): print name,'is',age,'years old.' #输出如下 Anne is 12 years old. Beth is 23 years old. George is 78 years old. Damon is 67 years old.
程序可以同时迭代两个序列
而内建的zip命令就可以用来进行并行迭代,可以把两个序列压缩在一起,然后返回一个元组的列表
name = ['Anne','Beth','George','Damon'] age = [12,23,78,67] for i in range(len(name)): print name[i],'is',age[i],'years old.' #输出如下 Anne is 12 years old. Beth is 23 years old. George is 78 years old. Damon is 67 years old.
zip函数也可以作用于人一多的序列。关于他的很重要的一点是zip可以处理不等长的序列,当最短的序列“用完”的时候就会停止
zip(range(5),xrange(1000))
输出:[(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)]
在上面的代码中,不推荐用range替换掉xrange,尽管只需要前5个数字,但是range会计算出所有的数字,这需要花费较长的时间
2.按索引迭代
有时候想要迭代访问序列中的对象,同时还要获取当前对象的索引
方法一:
for string in strings: if 'xxx' in string: index = strings.index(string) strings[index] = '[censored]'
方法二:
index = 0 for string in strings: if 'xxx' in string: strings[index] = '[censored]' index += 1
方法三:
使用内建的enumerate函数
for index,string in enumerate(strings): if 'xxx' in string: string[index] = '[censored]'
上面的用法还是没搞懂怎么更好的使用
3.翻转和排序迭代:reversed和sorted
它们作用于任何序列或可迭代对象上,不是原地修改对象,而是返回翻转或排序后的版本
>>> sorted([4,3,5,2,3,6,9,0]) [0, 2, 3, 3, 4, 5, 6, 9] >>> sorted('Hello,world!') ['!', ',', 'H', 'd', 'e', 'l', 'l', 'l', 'o', 'o', 'r', 'w'] >>> list(reversed('Hello,world!')) ['!', 'd', 'l', 'r', 'o', 'w', ',', 'o', 'l', 'l', 'e', 'H'] >>> ''.join(reversed('Hello,world!')) '!dlrow,olleH'
5.5.5 跳出循环
1.break
from math import sqrt for n in range(99,0,-1): root = sqrt(n) if root == int(root): print root,n break #结果如下,求出0-100范围内最大的平方数 9.0 81
2.continue
它最基本的意思是:跳过剩余的循环体,但是不结束循环。当循环体很大且很复杂的时候比较有效。
它会将当前的迭代结束,“跳”到下一轮循环开始
例1:
for x in seq: if condition1:continue if condition2:continue if condition3:continue do_something() do_something_else() do_another_thing() etc()
例2:
for x in seq: if not(condition1 or condition1 or condition1): do_something() do_something_else() do_another_thing() etc()
3.while True/break习语:
while True: word = raw_input('Please enter a word: ') if not word: break #处理word print 'The word was ' + word
4.循环中的else语句
from math import sqrt for n in range(99,0,-1): root = sqrt(n) if root == int(root): print root,n break else: print "Don't find it."
5.6 列表推导式:轻量级循环
例:
>>> [x*x for x in range(5)] [0, 1, 4, 9, 16] >>> [x*x for x in range(10) if x%3 == 0] [0, 9, 36, 81] >>> [(x,y) for x in range(3) for y in range(3) if y<=x] [(0, 0), (1, 0), (1, 1), (2, 0), (2, 1), (2, 2)] >>> [(x,y) for x in range(3) for y in range(3)] [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]
问题:筛选出名字首字母相同的男孩和女孩
方法一:
girls = ['alice','bernice','clarice'] boys = ['chris','arnord','bob'] print [boy + ' + ' + girl for boy in boys for girl in girls if boy[0]==girl[0]] #结果如下 ['chris + clarice', 'arnord + alice', 'bob + bernice']
方法二:
girls = ['alice','bernice','clarice','bibl'] boys = ['chris','arnord','bob'] letterGirls = {} for girl in girls: letterGirls.setdefault(girl[0],[]).append(girl) print letterGirls print [Boy + ' + ' + Girl for Boy in boys for Girl in letterGirls[Boy[0]]] #结果如下 {'a': ['alice'], 'c': ['clarice'], 'b': ['bernice', 'bibl']} ['chris + clarice', 'arnord + alice', 'bob + bernice', 'bob + bibl']
这个程序建造了一个叫做letterGirl的字典,其中的每一项都把单字母作为键,以女孩名字组成的列表作为值。在字典建立后,列表推导式循环整个男孩集合,并且查找那些和当前男孩名字首字母相同的女孩集合。这样列表推导式就不用尝试手游的男孩、女孩的组合,检查首字母是否匹配。
5.7 三人行:pass、del、exec
5.7.1 什么都没发生:pass
有的时候,程序什么事情都不用做
那么什么时候会用到pass?
他可以在代码中做占位符使用,比如程序要一个if语句,然后测试,但是缺少其中一个语句块的代码,就会用到:
if name == 'Raplh Auldus Melish': print "Welcome!" elif name == 'Enid': #在elif这个代码块中,必须要有一个执行语句,否则空代码块在Python中是非法的,解决方法就是加一个pass #还没完 pass elif name == 'Bill Gates': print "Access Denied!"
5.7.2 使用del删除
一般来说,python会删除那些不再使用的对象,进行内存的垃圾回收
del语句不仅会移除一个对象的引用,也会移除那个名字本身
>>> x = 1 >>> del x >>> x Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'x' is not defined
看起来简单,理解起来难
例:x和y都指向同一个列表
>>> x = ["Hello",'World'] >>> y = x >>> y[1] = "python" >>> x ['Hello', 'python']
会有人认为删除x之后,y就会随之消失了,但是并非如此
>>> del x >>> x Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'x' is not defined >>> y ['Hello', 'python']
为什么?x和y都指向同一个列表。但是删除x并不会影响y。原因就是删除的只是名称,不是列表本身(值)。事实上,在python中是没有办法删除值得,也不需要过多考虑删除值的问题,因为某个值不再使用的时候,python解释器会负责内存的回收。
5.7.3 使用exec和eval执行和求值字符串
1.exec
执行一个字符串的语句
>>> exec "print 'Hello,world!'" Hello,world!
使用简单的exec绝不是好事。很多钱款下可以给它提供命名空间--可以放置变量的地方。你想这样做,从而使代码不会干扰命名空间(也就是你的变量),比如,下面的代码中使用了名称sqrt:
>>> from math import sqrt >>> exec "sqrt = 1" >>> sqrt(4) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'int' object is not callable
为什么这样做?exec语句最有用的地方在于可以动态的创建代码字符串。如果字符串是从其他地方获得的---很可能是用户---那么几乎不能确定其中到底有什么代码。所以为了安全起见,可以增加一个支点,起到命名空间的作用。
命名空间的概念,或称为作用域(scope)
>>> from math import sqrt >>> scope = {} >>> exec 'sqrt = 1' in scope >>> sqrt(4) 2.0 >>> scope['sqrt'] 1
可以看到,潜在的破坏性代码并不会覆盖sqrt函数,原来的函数能正常工作,而通过exec赋值的变量sqrt只在它的作用域内有效。
2.eval
是类似于exec的内建函数
跟exec一样,eval也可以使用命名空间。尽管表达式几乎不像语句那样为变量重新赋值。(实际上,可以给eval语句提供两个命名空间,一个是全局的,一个是局部的。全局的必须是字典,局部的可以是任何形式的映射。)
5.8 小结
1.打印:print
2.导入:import
3.赋值:序列解包、链式赋值
4.块:通过缩排使语句成组的一种方法
5.条件
6.断言
7.循环
8.列表推导式
9.pass、del、eval、exec