4.7 集合(Set)操作
集合是容器,用len可以得到内部元素个数。
集合是可迭代对象,其迭代顺序是随机的。
4.7.1 成员检测
k in S 用来检测S中是否包括元素k。
4.7.2 Set方法
非改变方法(不改变应用方法的对象本身,它们也可以应用到fronzeset对象上):
S.copy( )
返回集合的浅拷贝。
S.difference(S1) (S – S1)
返回存在于S中,但不存在于S1中的元素。
S.intersection(S1) (S & S1)
返回S与S1的交集。
S.issubset(S1)
若S是S1的子集,则返回true,否则为false。
S.issuperset(S1)
若S1是S的子集,则返回true,否则为false。等同于S1.issubset(S))
S.symmetric_difference(S1) (S ^ S1)
返回不同时存在于S及S1中的元素。
S.union(S1) (S | S1)
返回S与S1的合集。
改变方法(将会改变应用的对象本身,所以只能用于set对象;除pop方法外,只返回None。所有下列方法中引用到的x必须为可散列对象):
S.add(x)
添加新元素x。若x已存在,则不做任何处理。
S.clear( )
移除S中的所有元素,将S清空。
S.discard(x)
移除元素x。若x不存在,则不做任何处理。
S.pop( )
移除并返回S中的一个元素。
S.remove(x)
移除元素x。若x不存在,则抛出异常KeyError。
difference_update (S -= S1)
intersection_update (S &= S1)
symmetric_difference_update (S ^= S1)
update (S |= S1)
以上四个方法的处理算法等同于同名的非改变方法,只是这四个方法会改变调用方法的集合对象本身(update等同于union),同时只是返回None。
特别注意的是,针对这八个方法(四个不改变方法与对应的四个改变方法),若通过方法调用,则参数S1可以使用任意可迭代对象(唯一的要求是,由此可迭代对象遍历得到的对象必须是可散列对象),但是若通过操作符运算或参数赋值运算来处理,则S与S1必须是set或frozenset。
利用pop方法,你可以一边迭代遍历Set,一边抛弃此元素,对于大集合来说,可以节省部分内存。
4.8 字典
首先,字典是容器对象,所以可以用len函数来获取其内部元素(键/值对)的个数。其次,字典是可迭代对象,但是它只针对key进行随机遍历,对于函数min(D),结果是最小的key值。
4.8.1 成员检测
k in D可以用来检测k是否是字典D的一个键值,若是则返回true,否则为false。
4.8.2 索引操作
字典中的值通过索引来访问:v=D[k]。针对无效的k,系统将会抛出异常。
d = { 'x':42, 'y':3.14, 'z':7 }
d['x'] # 42
d['z'] # 7
d['a'] # 抛出KeyError异常
通过在赋值语句中使用一个新的键值,就可以往字典中添加新的项目(键/值对)。
d = { 'x':42, 'y':3.14}
d['a'] = 16 # d is now {'x':42, 'y':3.14,'a':16}
使用del语句:del D[k]可以移除与索引k相对应的项目(键/值对)。
4.8.3 字典操作
以下的方法中,k必须为可散列对象,x可以为任意对象。
非改变方法(不会改变应用方法的对象本身):
D.copy( )
返回字典的浅拷贝。
D.has_key(k)
若存在键值k,则返回true,否则false。
D.items( )
返回一个新的包含字典D中所有项目(键值对)的List。
D.keys( )
返回一个新的包含字典D中所有键值的List。
D.values( )
返回一个新的包含字典D中所有值的List。
D.iteritems( )
返回基于D中所有项目(键值对)之上的迭代器。
D.iterkeys( )
返回基于D中所有键值之上的迭代器。
D.itervalues( )
返回基于D中所有值之上的迭代器。
D.get(k[, x])
返回字典中与键值k相对的值,若此键值不存在,则返回x,若没有指定x,则返回None。
改变方法(改变应用此方法的对象):
D.clear( )
移除字典D中所有项目,D成为一个空字典。
D.update(D1)
针对字典D1中的所有键值k,将D[k]设置为等于D1[k]。
D.setdefault(k[, x])
若k为字典D中合法的键值,则返回D[k],否则,将D[k]的值设置为x,并返回x。
D.pop(k[, x])
若k为字典D中合法的键值,则移除并返回D[k],否则,返回x。若没有指定x,则抛出异常。
D.popitem( )
移除并返回字典D中一个项目(键值对)。
items、keys、以及values方法在返回新的List时都按一定顺序排序,如果多次调用这些方法,且在调用期间没有进行插入或移除操作,则将会一直保持此顺序。
iteritems、iterkeys、以及itervalues方法返回与上述三个方法的List结果一致的迭代器,且使用迭代器只需要更少的内存。只是要注意,在使用迭代器时,不能对更改键值集合,即不能插入或移除任何键值,而对于items、keys、以及values方法在返回的List则没有此限制。
当你只需要使用一次字典,则可以使用popitem方法,它比items方法要节省内存。
setdefault与get方法的效果一样,只是当key不存在时,setdefault添加一个新项目,并将x设置为D[k]的值。同样对于pop方法,它与get一样返回字典项目,并随后将其移除。
要注意对于pop与get方法,若key不存在,get返回None,而pop抛出异常。
在Python2.4中,update方法还可以接受包含键值对的可迭代对象作为参数。
4.9 print语句
print语句由关键字print加上零个或多个由逗号分隔的表达式组成。可以方便地用文本方式来显示值,对于debug特别有用。print语句针对每个表达式x显示的文本与str(x)的结果一致。
默认情况下,print会在各个表达式间插入空格,并在最后一个表达式后插入一个换行符,除非你在最后一个表达式后面接了一个逗号。
letter = 'c'
print "give me a", letter, "..." # prints: give me a c... answer = 42
print "the answer is:", answer # prints: the answer is: 42
print的输出目标是文件或类文件对象,即sys模块中stdout属性的值。若要重定向输入目标,如文件对象f,则可以用以下语句:
print >>f, rest of print statement
若f为Nonw,则目标将会是sys.stdout,就像你不给出 >>f 的效果一样。
4.10. 流程控制语句
4.10.1. if 语句
if expression:
statement(s)
elif expression:
statement(s)
elif expression:
statement(s)
...
else:
statement(s)
可以使用任意Python表达式作为if或elif语句的条件。任何非零的数字或非空的容器都为true;零、None、或空容器都表示false。当你要检测布尔值时,请直接使用:
if x:
而不要使用如下格式:
if x is True:
if x == true:
if bool(x):
若if语句的条件为真,则Python执行它的子语句,否则,将会对每个elif按顺序进行运算,碰到第一个为真的条件时,就运行这个子语句,之后整个if语句运行结束。
4.10.2. while 语句
while expression:
statement(s)
在while语句中也可以包含else子句,break子句,以及continue子句。
4.10.3. for 语句
for语句由一个可迭代对象进行控制:
for target in iterable:
statement(s)
for语句也可以包含else、break、以及continue子句。
for语句中的控制变量target也可以是多个标识符,条件是可迭代对象中的项目必须是可迭代对象,且此可迭代对象中包含的对象数目与标识符数一致。如针对字典d:
for key, value in d.items( ):
if not key or not value: # keep only true keys and values
del d[key]
若可迭代对象的底层对象不是一个不变对象,则要注意在循环的过程中不要改变此对象。
若循环于一个List之上,不要插入、添加、或移除任何项目(重绑定是可以的)。
若循环于一个字典之上,不要添加或移除任何项目(重绑定是可以的)。
若循环于一个集合之上,不要添加或移除任何项目(任何改变都是不允许的)。
4.10.3.1. 迭代器
迭代器是这样的一个对象,假设为对象i,它拥有无参数方法i.next()供调用,i.next()返回可迭代对象的下一个项目,或者,若已迭代到了最后,则抛出一个StopIteration异常。
只要在你自己的类中定义这样一个next方法,就可以让类的实例成为可迭代对象。
大部分迭代器都可以隐式或显式地调用内置函数iter来实现。
调用Generator也会返回一个迭代器。
如下例,for语句会隐式地调用iter来得到一个迭代器。
for x in c:
statement(s)
改成对等的显式调用以后,如下例如示:
_temporary_iterator = iter(c)
while True:
try: x = _temporary_iterator.next( )
except StopIteration: break
statement(s)
然而,若iter(c)返回的迭代器i的next()方法永远不会抛出StopIteration异常的话,for循环就永远不会停止(除非在循环体中有合适的break或return语句,或抛出异常)。iter(c)方法将会按顺序调用特定的方法c.__iter__()来得到基于c的一个迭代器。
模块itertools提供了许多好的构建与操纵迭代器的途径。
4.10.3.2. range与xrange函数
基于一个整数序列进行循环是最常见的循环场景,Python提供了内置的range与xrange来生成并返回整数序列。
要循环n次可以使用如下语句:
for i in xrange(n):
statement(s)
range(x)返回一个List,包含有从0(包括在序列中)开始到x(不包括在序列中)结束的连续整数,对应的,range(x,y)返回的List包含有从x(包括在序列中)开始到y(不包括在序列中)结束的整数。而range(x,y,step)还可以为序列中的整数加上步长,若步长小于0,则从x开始进行递减。若step等于零,则抛出异常。
range函数返回一个普通的List对象,可以用于任意目的,但是xrange函数返回的是一个特定目的的对象(不是一个List对象),专用于需要迭代处理的地方,如for语句中。(请注意,为了兼容性的考虑,xrange返回的并不是一个可迭代对象,若你需要一个可迭代对象,请使用iter(xrange(…)))。这个由xrange返回的特定对象相比List而言节省内存,但是在其上进行循环操作时又需要花费比List更多的开销。
所以,基本上在你需要用一个整数序列时,可以一直使用range而不使用xrange。
>>> print range(1, 5)
[1, 2, 3, 4]
>>> print xrange(1, 5)
xrange(1, 5)
在上面语句中,range返回了一个普通List,而xrange返回了一个特定的xrange类型的对象。
4.10.3.3. List解析
for循环的一个常用场景是,用一个表达式对可迭代对象的每个元素进行相应的处理,并得到一个新的结果列表。这种表达式被称为列表解析,因而不再需要通过一个语句块来完成,你可以在任何可以使用表达式的场合直接使用它(如函数调用的一个参数,return语句,或作为其它表达式的子表达式)。
列表解析语法如下:
[ expression for target in iterable lc-clauses ]
其中target与iterable的用法与一般的普通语句一样,只是要注意若iterable中的项目是tuple,则target中变量的个数要与之保持一致(如使用字典作为iterable,则target必须是由两个变量组成的变量组)。
lc-clauses是一组零个或多个子句,其格式如下:
for target in iterable
if expression
列表解析是与for循环有同等效果的语句,如:
result1 = [x+1 for x in some_sequence]
等同于:
result2 = []
for x in some_sequence:
result2.append(x+1)
下面是使用if子句的例子:
result3 = [x+1 for x in some_sequence if x>23]
等同于:
result4 = []
for x in some_sequence:
if x>23:
result4.append(x+1)
下面是使用for子句的例子:
result5 = [x+y for x in alist for y in another]
等同于:
result6 = []
for x in alist:
for y in another:
result6.append(x+y)
从上面的例子中,可以看到对于具有多个for子句的列表解析,for循环的嵌套顺序与它们在解析语句中出现的顺序一致。
4.10.4. break 语句
break语句用来终止循环语句。若在嵌套循环中使用,则break只会终止包含它的那一层循环。
4.10.5. continue 语句
continue语句将会结束针对当前的迭代值的循环,程序将会继续此循环的下一个迭代值。
4.10.6. 循环语句中的else 子句
while与for语句可以在尾部拥有一个可选的else子句。如果循环正常结束(for语句用完了所有的迭代值,while语句的每件变成为false;若使用了break、return或抛出了异常,则为非正常结束),则将会运行相应的else子句,否则,不运行else子句。
可以使用else子句来检测循环是否正常结束。
for x in some_container:
if is_ok(x): break # item x is satisfactory, terminate loop
else:
print "Warning: no satisfactory item was found in container"
x = None
4.10.7. pass语句
在Python组合语句中的语句体至少必须要有一条语句,若你不需要程序做任何事,则可以使用pass语句,表示不做任何事,仅仅作为一个占位符存在。
请注意,对于空的def或class语句,你也可以使用docstring来代替pass语句。当然,你也可以使用pass语句。
4.10.8. try与raise语句
Python支持异常处理机制,包括有try、except、finnally、以及else子句。
程序可以使用raise语句来明确地引发一个异常。当异常发生时,程序正常的控制流程将会停止,Python会自动寻找一个合适的异常处理器。
4.10.9. with语句
在Python 2.5中,新增了with语句,作为try/finally语句的一个更可读的替代。