最近看了廖雪峰老师的博客中关于python的内容,感觉收获良多。
廖雪峰的博客:http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000
1、关于.py文件的编码问题
这个问题困扰我很久,一直疑惑于.py文件中的中文字符串常量的编码问题。
我们经常在程序的第一行写入:
# -*- coding: utf-8 -*-
以为这样,整个文件就是utf-8的编码了。其实并不是,在我的实践中,我发现该文件下的中文字符串常量,并不是utf-8编码的。我尝试使用以下语句:
'蛋糕'.decode('GBK').encode('utf8')
这样才能得到utf-8下的中文字符串。这是为什么呢?
原因在于,在Windows系统环境下,一个文件的默认编码为ANSI编码,其中的中文字符默认编码为GBK。
如果我们在Notepad++中,将.py文件格式改变为UTF-8 without BOM,这样才可以保证文件中的中文字符串为utf-8编码。
而第一行注释又有什么意义呢?
该注释是为了告诉Python解释器,按照UTF-8编码读取源代码,否则,你在源代码中写的中文输出可能会有乱码。
看个例子:
# -*- coding:utf-8 -*-
a=['中文']
print a
同样的文件,在记事本编辑环境下,输出为:
['\xd6\xd0\xce\xc4']
可以验证编码为GBK。
而在notepad下以UTF-8 without BOM编辑,输出为:
['\xe4\xb8\xad\xe6\x96\x87']
为utf-8编码。
如果.py文件本身使用UTF-8编码,并且也申明了# -*- coding: utf-8 -*-,打开命令提示符测试就可以正常显示中文。
2、关于元组tuple
除list外,另一种有序列表叫元组:tuple。tuple和list非常类似,但是tuple一旦初始化就不能修改。
获取元素可以使用下标,但是无法修改,没有append、insert方法。
如果要定义一个只有1个元素的tuple,记得在后面加逗号。
3、关于dict
dict使用的key-value存储方式,在放进去的时候,必须根据key算出value的存放位置,这样,取的时候才能根据key直接拿到value。
dict可以用在需要高速查找的很多地方,在Python代码中几乎无处不在,正确使用dict非常重要,需要牢记的第一条就是dict的key必须是不可变对象。
这是因为dict根据key来计算value的存储位置,如果每次计算相同的key得出的结果不同,那dict内部就完全混乱了。这个通过key计算位置的算法称为哈希算法(Hash)。
要保证hash的正确性,作为key的对象就不能变。在Python中,字符串、整数等都是不可变的,因此,可以放心地作为key。而list是可变的,就不能作为key。
4、关于set
set和dict类似,也是一组key的集合,但不存储value。由于key不能重复,所以,在set中,没有重复的key。
set和dict的唯一区别仅在于没有存储对应的value,但是,set的原理和dict一样,所以,同样不可以放入可变对象,因为无法判断两个可变对象是否相等,也就无法保证set内部“不会有重复元素”。试试把list放入set,看看是否会报错。
5、不可变对象
对于不变对象来说,调用对象自身的任意方法,也不会改变该对象自身的内容。相反,这些方法会创建新的对象并返回,这样,就保证了不可变对象本身永远是不可变的。
6、返回多个值
import math
def move(x, y, step, angle=0):
nx = x + step * math.cos(angle)
ny = y - step * math.sin(angle)
return nx, ny
多个值之间使用逗号分隔,这样返回的是一个元组tuple。
7、默认参数
关于默认参数,有个大坑例子:
def add_end(L=[]):
L.append('END')
return L
使用默认参数调用时:
>>> add_end()
['END']
>>> add_end()
['END', 'END']
>>> add_end()
['END', 'END', 'END']
原因解释如下:
Python函数在定义的时候,默认参数L的值就被计算出来了,即[],因为默认参数L也是一个变量,它指向对象[],每次调用该函数,如果改变了L的内容,则下次调用时,默认参数的内容就变了,不再是函数定义时的[]了。
所以,定义默认参数要牢记一点:默认参数必须指向不变对象!
8、可变参数
def calc(*numbers):
sum = 0
for n in numbers:
sum = sum + n * n
return sum
调用:
>>> calc(1, 2, 3)
14
>>> calc(1, 3, 5, 7)
84
9、关键字参数
def person(name, age, **kw):
print 'name:', name, 'age:', age, 'other:', kw
调用:
>>> person('Bob', 35, city='Beijing')
name: Bob age: 35 other: {'city': 'Beijing'}
>>> person('Adam', 45, gender='M', job='Engineer')
name: Adam age: 45 other: {'gender': 'M', 'job': 'Engineer'}
10、列表生成式
好像只能用来生成列表?
>>> [m + n for m in 'ABC' for n in 'XYZ']
['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']
11、生成器
要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:
>>> L = [x * x for x in range(10)]
>>> L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g = (x * x for x in range(10))
>>> g
<generator object <genexpr> at 0x104feab40>
定义generator的另一种方法,如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator:
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n = n + 1
最难理解的就是generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。