笔记概述
这个笔记是我为了把学过的python知识记录下来,以便以后查看。由于现在对python的理解还不够深入,我只会记录一些python中有些难理解的部分,而不会去做总结性的概括和归纳。随着python的不断学习,会持续更新这个笔记。
动态类型
python是一种动态类型(dynamic typing)的语言, python中的变量不需要提前申明类型,变量的类型由python自己决定。
例如:
a = 3
这句在python中应该理解为先生成“3”这个整型的对象,然后在用a指向这个对象。再次赋值:
a = 5
此时a又指向了“5”这个对象。此时对象“3”不再有引用指向它了,python会自动将没有引用指向的对象销毁(destrcut), 释放其内存。
上面的“3”和“5”都是int型的,和float,tuple,string这些都属于不可变数据对象(immutable object)。所以即使执行下面的语句:
a = 3 b = a b = 5
虽然b指向了a所指向的对象“3”,但是由于“3”是不可变的数据对象,当对b再次赋值的时候不会改变“3”本身,而是重新生成“5”这个对像,并将b重新指向“5”。python中的变量就像一个标签(tag)贴在它所代表的对象上,当然这个标签也可以撕下来重新贴在另一个对象上。
既然有不可变的数据对象,那么也肯定有可变数据对象(mutable object)。python的字典(dictionary)类型,就要求其中的key不可以是可变数据类型的,也就是说key不可以是列表(list), 字典(dict)等可变的数据类型。
对于可变数据类型比如列表(list), 当变量指向它的时候,情况会有些不同。考虑下面的代码:
a = [1, 2, 3] b = a b[2] = 3
第一行说明a绑定了一个list对象(想象tag a贴在list [1, 2, 3]上), 下面一行是将b指向a指向的列表对象即 [1, 2, 3], 到这一句都和前面的整型对象一样,但最后一句就不一样了,不是将b重新贴在"3"这个整形对象上,而是改变了list中的值,a同时也会发生改变。其实从b[2]就可以看出,因为带了个"2", b不能再次贴在其它变量上了。
循环对象
关于循环对象难免要涉及以下一些概念:生成器(generator), 迭代器(iterator), list conprehension(表理解,没法翻译)
生成器(generator)
说生成器先从range这个最常用的内置函数说起,在python2.x版本中有:
>>> range(0, 10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
range函数直接返回的是一个列表,range通常用于循环中,这样对于循环次数过大的语句,就必须先生成那个大列表,这样效率不高。所以很多人用xrange来代替range,且看下面代码:
>>> xrange(0, 10) xrange(10) >>> help(xrange) Help on class xrange in module __builtin__: class xrange(object) | xrange(stop) -> xrange object | xrange(start, stop[, step]) -> xrange object | | Like range(), but instead of returning a list, returns an object that | generates the numbers in the range on demand. For looping, this is | slightly faster than range() and more memory efficient.
xrange的用法和range几乎一模一样,只是它不直接生成一个列表,而是在每次循环的时候生成一个所需的数字用于循环。帮助中也说了这样会稍微快一点,也节省了一些内存空间。可以看到xrange函数返回的是xrange的对象,这样的对象也叫做生成器(generator)。自己也可以写生成器,通过自己写的生成器就能更加清晰地理解什么是生成器。
def fab(n): a = 0 b = 1 c = 1 i = 0 while i < n: yield c c = a + b a = b b = c i = i + 1
生成器的编写和函数类似,在需要return的地方改为yield,生成器可以有多个yield。当生成器遇到一个yield的时候会停下来,返回yield后面的值,等再次调用生成器的时候,继续刚才停下的地方执行。生成器自身又构成一个循环器,每循环一次,使用一个yield的值。上面的代码是生成斐波纳挈数列,下面我们来使用它:
>>> for num in fab(5): print(num) 1 1 2 3 5
或者这样使用:
>>> list(fab(10))
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
这样使用斐波纳挈数列是不是显得极为方便,而且效率也很高。这样再看xrange就很容易明白什么是生成器了。(python 3.x中没有了xrange函数,range函数也不再返回一个list,而是返回一个循环对象。)
迭代器(iterator)
迭代器和生成器几乎就是一个概念,但具体深究,循环对象和for循环调用之间还有一个中间层,就是要将循环对象转换成迭代器(iterator)。这一转换是通过使用iter()函数实现的。但从逻辑层面上,常常可以忽略这一层,所以循环对象和迭代器常常相互指代对方。
表推导(list conprehension)
假设你有一个列表,现在需要你生成一个每个元素是原来列表的平方的新的列表,这很容易做到:
l = range(5) new_l = [] for value in l: new_l.append(value ** 2)
但是python不推荐上面的写法,因为不优雅。可以这样优雅的来实现:
new_l = [i ** 2 for i in range(5)]
几个常用的内置函数zip,map,filter,reduce
zip()函数
看下面的例子:
>>> fruit = ["apple", "banana", "orange"] >>> price = [8.5, 4.0, 3.5] >>> list(zip(fruit, price)) [(‘apple‘, 8.5), (‘banana‘, 4.0), (‘orange‘, 3.5)]
由于zip函数返回的也是一个循环对象,所以我们用list方法将它转化为一个列表。zip函数依次取各个参数中的一个元素组成一个新的元素。下面用一个例子来说明zip函数的用法:
def transpose(data): ‘‘‘ data is a list of list representing a matrix. return the transposed matrix. ‘‘‘ return [list(x) for x in zip(*data)]
上面函数的功能是输入一个矩阵,返回它的转置矩阵。