数据类型
dict的第一个特点是查找速度快,无论dict有10 个元素还是10 万个元素,查找速度都一样。而list 的查找速度随着元素增加而逐渐下降。
不过dict的查找速度快不是没有代价的,dict的缺点是占用内存大,还会浪费很多内容,list 正好相反,占用内存小,但是查找速度慢。
dict的作用是建立一组 key 和一组 value 的映射关系,dict的key是不能重复的。
有的时候,我们只想要 dict 的 key,不关心 key 对应的 value,目的就是保证这个集合的元素不会重复,这时,set 就派上用场了。
set 持有一系列元素,这一点和 list 很像,但是set 的元素没有重复,而且是无序的,这点和 dict 的 key很像。
创建 set 的方式是调用 set () 并传入一个 list ,list 的元素将作为set 的元素:
>>> s = set (['A' , 'B' , 'C' ])
可以查看 set 的内容:
>>> print s
set (['A' , 'C' , 'B' ])
Python之什么是函数
抽象是数学中非常常见的概念。举个例子:
计算数列的和,比如:1 + 2 + 3 + ... + 100 ,写起来十分不方便,于是数学家发明了求和符号∑,可以把1 + 2 + 3 + ... + 100 记作:
100
∑n
n=1
这种抽象记法非常强大,因为我们看到∑就可以理解成求和,而不是还原成低级的加法运算。
而且,这种抽象记法是可扩展的,比如:
100
∑(n²+1 )
n=1
还原成加法运算就变成了:
(1 x 1 + 1 ) + (2 x 2 + 1 ) + (3 x 3 + 1 ) + ... + (100 x 100 + 1 )
-------
任务
sum()函数接受一个list作为参数,并返回list所有元素之和。请计算 1 *1 + 2 *2 + 3 *3 + ... + 100 *100 。
L = []
x=1 ;
while x<=100 :
L.append(x*x)
x+=1
print sum(L)
输出结果338350
**自定义函数**
在Python中,定义一个函数要使用 def 语句,依次写出函数名、括号、括号中的参数和冒号: ,然后,在缩进块中编写函数体,函数的返回值用 return 语句返回。
**任务**
一元二次方程的定义是:ax² + bx + c = 0
请编写一个函数,返回一元二次方程的两个解。
请参考求根公式:x = (-b±√(b²-4 ac)) / 2 a
注意:Python的math包提供了sqrt()函数用于计算平方根。
import math
def quadratic_equation (a, b, c) :
t = math.sqrt(b * b - 4 * a * c)
return (-b + t) / (2 * a),( -b - t )/ (2 * a)
print quadratic_equation(2 , 3 , 0 )
print quadratic_equation(1 , -6 , 5 )
**递归函数**
在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。
举个例子,我们来计算阶乘 n! = 1 * 2 * 3 * ... * n,用函数 fact(n)表示,可以看出:
fact(n) = n! = 1 * 2 * 3 * ... * (n-1 ) * n = (n-1 )! * n = fact(n-1 ) * n
所以,fact(n)可以表示为 n * fact(n-1 ),只有n=1 时需要特殊处理。
于是,fact(n)用递归的方式写出来就是:
def fact (n) :
if n==1 :
return 1
return n * fact(n - 1 )
上面就是一个递归函数。可以试试:
>>> fact(1 )
1
>>> fact(5 )
120
int()函数的第二个参数是转换进制,如果不传,默认是十进制
我们来定义一个计算 x 的N次方的函数:
def power (x, n) :
s = 1
while n > 0 :
n = n - 1
s = s * x
return s
假设计算平方的次数最多,我们就可以把 n 的默认值设定为 2 :
def power (x, n=2 ) :
s = 1
while n > 0 :
n = n - 1
s = s * x
return s
这样一来,计算平方就不需要传入两个参数了:
>>> power(5 )
25
由于函数的参数按从左到右的顺序匹配,所以默认参数只能定义在必需参数的后面
**可变参数**
可变参数的名字前面有个 * 号
可变参数也不是很神秘,Python解释器会把传入的一组参数组装成一个tuple传递给可变参数,因此,在函数内部,直接把变量 args 看成一个 tuple 就好了。
def average (*args) :
sum = 0.0
if len(args) == 0 :
return sum
for x in args:
sum = sum + x
return sum / len(args)
print average()
print average(1 , 2 )
print average(1 , 2 , 2 , 3 , 4 )
对list进行切片
L[0 :3 ]表示,从索引0 开始取,直到索引3 为止,但不包括索引3 。即索引0 ,1 ,2 ,正好是3 个元素。
只用一个 : ,表示从头到尾:>>> L[:]
['Adam' , 'Lisa' , 'Bart' , 'Paul' ]
切片操作还可以指定第三个参数:
>>> L[::2 ]
['Adam' , 'Bart' ]
*第三个参数表示每N个取一个*,上面的 L[::2 ] 会每两个元素取出一个来,也就是隔一个取一个。
把list换成tuple,切片操作完全相同,只是切片的结果也变成了tuple。
**任务**
range()函数可以创建一个数列:
>>> range(1 , 101 )
[1 , 2 , 3 , ..., 100 ]
请利用切片,取出:
1. 前10 个数;
2. 3 的倍数;
3. 不大于50 的5 的倍数
L = range(1 , 101 )
print L[:10 ]
print L[2 ::3 ]
print L[4 :50 :5 ]
**对字符串切片**
字符串 'xxx' 和 Unicode字符串 u'xxx' 也可以看成是一种list,每个元素就是一个字符。因此,字符串也可以用切片操作,只是操作结果仍是字符串:
>>>'ABC' [1 ]
'B'
>>> 'ABCDEFG' [:3 ]
'ABC'
>>> 'ABCDEFG' [-3 :]
'EFG'
>>> 'ABCDEFG' [::2 ]
'ACEG'
迭代
在Python中,如果给定一个list或tuple,我们可以通过for 循环来遍历这个list或tuple,这种遍历我们成为迭代(Iteration)。
在Python中,迭代是通过 for ... in 来完成的,而很多语言比如C或者Java,迭代list是通过下标完成的
可以看出,Python的for 循环抽象程度要高于Java的for 循环。
因为 Python 的 for 循环不仅可以用在list或tuple上,还可以作用在其他任何可迭代对象上。
因此,迭代操作就是对于一个集合,无论该集合是有序还是无序,我们用 for 循环总是可以依次取出集合的每一个元素。
注意: 集合是指包含一组元素的数据结构,我们已经介绍的包括:
1. 有序集合:list,tuple,str和unicode;
2. 无序集合:set
3. 无序集合并且具有 key-value 对:dict
而迭代是一个动词,它指的是一种操作,在Python中,就是 for 循环。
**索引迭代**
Python中,迭代永远是取出元素本身,而非元素的索引。
对于有序集合,元素确实是有索引的。有的时候,我们确实想在 for 循环中拿到索引,怎么办?
方法是使用 enumerate() 函数:
>>> L = ['Adam' , 'Lisa' , 'Bart' , 'Paul' ]
>>> for index, name in enumerate(L):
... print index, '-' , name
...
0 - Adam
1 - Lisa
2 - Bart
3 - Paul
使用 enumerate() 函数,我们可以在for 循环中同时绑定索引index和元素name。但是,这不是 enumerate() 的特殊语法。实际上,enumerate() 函数把:
['Adam' , 'Lisa' , 'Bart' , 'Paul' ]
变成了类似:
[(0 , 'Adam' ), (1 , 'Lisa' ), (2 , 'Bart' ), (3 , 'Paul' )]
因此,迭代的每一个元素实际上是一个tuple:
for t in enumerate(L):
index = t[0 ]
name = t[1 ]
print index, '-' , name
如果我们知道每个tuple元素都包含两个元素,for 循环又可以进一步简写为:
for index, name in enumerate(L):
print index, '-' , name
这样不但代码更简单,而且还少了两条赋值语句。
可见,索引迭代也不是真的按索引访问,而是由 enumerate() 函数自动把每个元素变成 (index, element) 这样的tuple,再迭代,就同时获得了索引和元素本身。
任务
zip()函数可以把两个 list 变成一个 list:
>>> zip([10 , 20 , 30 ], ['A' , 'B' , 'C' ])
[(10 , 'A' ), (20 , 'B' ), (30 , 'C' )]
在迭代 ['Adam' , 'Lisa' , 'Bart' , 'Paul' ] 时,如果我们想打印出名次 - 名字(名次从1 开始),请考虑如何在迭代中打印出来。
提示:考虑使用zip()函数和range()函数
?不会了怎么办
range(1 , ?) 可以创建出起始为 1 的数列。
参考代码:
L = ['Adam' , 'Lisa' , 'Bart' , 'Paul' ]
ll=zip(range(1 ,len(L)+1 ),L)
for index, name in zip(range(1 , len(L)+1 ), L):
print index, '-' , name
print ll
输出结果:
1 - Adam
2 - Lisa
3 - Bart
4 - Paul
[(1 , 'Adam' ), (2 , 'Lisa' ), (3 , 'Bart' ), (4 , 'Paul' )]
我们已经了解了dict对象本身就是可迭代对象,用 for 循环直接迭代 dict,可以每次拿到dict的一个key。
那这两个方法有何不同之处呢?
1. values() 方法实际上把一个 dict 转换成了包含 value 的list。
2. 但是 itervalues() 方法不会转换,它会在迭代过程中依次从 dict 中取出 value,所以 itervalues() 方法比 values() 方法节省了生成 list 所需的内存。
3. 打印 itervalues() 发现它返回一个 <dictionary-valueiterator> 对象,这说明在Python中,for 循环可作用的迭代对象远不止 list,tuple,str,unicode,dict等,任何可迭代对象都可以作用于for 循环,而内部如何迭代我们通常并不用关心。
如果一个对象说自己可迭代,那我们就直接用 for 循环去迭代它,可见,迭代是一种抽象的数据操作,它不对迭代对象内部的数据有任何要求。
**任务**
给定一个dict:
d = { 'Adam' : 95 , 'Lisa' : 85 , 'Bart' : 59 , 'Paul' : 74 }
请计算所有同学的平均分。
d = { 'Adam' : 95 , 'Lisa' : 85 , 'Bart' : 59 , 'Paul' : 74 }
sum = 0.0
for x in d.values():
sum+=x
print sum/len(d)
for y in d:
print y
**生产列表Python特有**
列表生成式则可以用一行语句代替循环生成上面的list:
>>> [x * x for x in range(1 , 11 )]
[1 , 4 , 9 , 16 , 25 , 36 , 49 , 64 , 81 , 100 ]
这种写法就是Python特有的列表生成式。利用列表生成式,可以以非常简洁的代码生成 list。
写列表生成式时,把要生成的元素 x * x 放到前面,后面跟 for 循环,就可以把list创建出来,十分有用,多写几次,很快就可以熟悉这种语法。
任务
请利用列表生成式生成列表 [1x2, 3x4, 5x6, 7x8, ... , 99x100]
提示:range(1 , 100 , 2 ) 可以生成list [1 , 3 , 5 , 7 , 9 ,... ]
?不会了怎么办
把每次循环的 x 变成列表中的元素 x * (x + 1 )
参考代码:
print [x * (x + 1 ) for x in range(1 , 100 , 2 )]
如果我们只想要偶数的平方,不改动 range()的情况下,可以加上 if 来筛选:
条件过滤
>>> [x * x for x in range(1 , 11 ) if x % 2 == 0 ]
[4 , 16 , 36 , 64 , 100 ]
有了 if 条件,只有 if 判断为 True 的时候,才把循环的当前元素添加到列表中。
**复杂的表达式用于生成Html**
复杂表达式
使用for 循环的迭代不仅可以迭代普通的list,还可以迭代dict。
假设有如下的dict:
d = { 'Adam' : 95 , 'Lisa' : 85 , 'Bart' : 59 }
完全可以通过一个复杂的列表生成式把它变成一个 HTML 表格:
tds = ['<tr><td>%s</td><td>%s</td></tr>' % (name, score) for name, score in d.iteritems()]
print '<table>'
print '<tr><th>Name</th><th>Score</th><tr>'
print '\n' .join(tds)
print '</table>'
注:字符串可以通过 % 进行格式化,用指定的参数替代 %s。字符串的join()方法可以把一个 list 拼接成一个字符串。
把打印出来的结果保存为一个html文件,就可以在浏览器中看到效果了:
<table border="1" >
<tr><th>Name</th><th>Score</th><tr>
<tr><td>Lisa</td><td>85 </td></tr>
<tr><td>Adam</td><td>95 </td></tr>
<tr><td>Bart</td><td>59 </td></tr>
</table>
任务
在生成的表格中,对于没有及格的同学,请把分数标记为红色。
提示:红色可以用 <td style="color:red" > 实现。
?不会了怎么办
如果我们用一个函数来替换字符串的格式化代码,可以得到更清晰的代码:
def generate_tr(name, score):
return '<tr><td>%s</td><td>%s</td></tr>' % (name, score)
tds = [generate_tr(name, score) for name, score in d.iteritems()]
这样,只需要修改 generate_tr() 函数,必要的时候把score标红。
参考代码:
d = { 'Adam' : 95 , 'Lisa' : 85 , 'Bart' : 59 }
def generate_tr(name, score):
if score < 60 :
return '<tr><td>%s</td><td style="color:red">%s</td></tr>' % (name, score)
return '<tr><td>%s</td><td>%s</td></tr>' % (name, score)
tds = [generate_tr(name, score) for name, score in d.iteritems()]
print '<table border="1">'
print '<tr><th>Name</th><th>Score</th><tr>'
print '\n' .join(tds)
print '</table>'
1. isinstance(x, str) 可以判断变量 x 是否是字符串;
2. 字符串的 upper() 方法可以返回大写的字母。
**多层表达式**
多层表达式
for 循环可以嵌套,因此,在列表生成式中,也可以用多层 for 循环来生成列表。
对于字符串 'ABC' 和 '123' ,可以使用两层循环,生成全排列:
>>> [m + n for m in 'ABC' for n in '123' ]
['A1' , 'A2' , 'A3' , 'B1' , 'B2' , 'B3' , 'C1' , 'C2' , 'C3' ]
翻译成循环代码就像下面这样:
L = []
for m in 'ABC' :
for n in '123' :
L.append(m + n)