Python
1 数据类型与基本数据结构
1.0 理解切片
1 | +---+---+---+---+---+---+ |
1.1 工厂函数
type()
int()
float()
str()
list()
——生成列表tuple()
——生成元组dict()
——生成字典bool()
set()
——生成可变集合
1.2 列表
keywords | function |
---|---|
list.append(x) |
在列表的末尾添加一个元素。相当于 a[len(a):] = [x] |
list.extend(iterable) |
使用可迭代对象中的所有元素来扩展列表。相当于 a[len(a):] = iterable |
list.len() |
返回当前list的长度 |
list.insert(i, x) |
在给定的位置插入一个元素。第一个参数是要插入的元素的索引,所以 a.insert(0, x) 插入列表头部, a.insert(len(a), x) 等同于 a.append(x) |
list.remove(x) |
移除列表中第一个值为 x 的元素。如果没有这样的元素,则抛出 ValueError 异常 |
list.pop([i]) |
删除列表中给定位置的元素并返回它。如果没有给定位置,a.pop() 将会删除并返回列表中的最后一个元素。[ ]的意思是可选参数。 |
list.clear() |
移除列表中的所有元素。等价于del a[:] |
list.index(x[,start[,end]]) |
返回列表中第一个值为 x 的元素的从零开始的索引。如果没有这样的元素将会抛出 ValueError 异常可选参数 start 和 end 是切片符号,用于将搜索限制为列表的特定子序列。返回的索引是相对于整个序列的开始计算的,而不是 start 参数 |
list.sort(key=None, reverse=False) |
对列表中的元素进行排序(参数可用于自定义排序,解释请参见 sorted() ) |
list.reverse() |
翻转列表的元素 |
list.copy() |
返回列表的一个浅拷贝,等价于 a[:] |
list.count(x) |
返回元素 x 在列表中出现的次数 |
[x*x for x in list] |
list comprehensions |
1.3 字典
keywords | function |
---|---|
dict.items() |
|
dict.keys() |
|
dict.values() |
|
{i: i*i for i in range(20, 31) if i%2 != 0} |
dictionary comprehensions |
1.4 字符串
1.4.1 基本概念
如果你不希望前置了 \
的字符转义成特殊字符,可以使用 原始字符串 方式,在引号前添加 r
即可:
1 | 'C:\some\name') # here \n means newline! print( |
字符串字面值可以跨行连续输入。一种方式是用三重引号:"""..."""
或 '''...'''
。字符串中的回车换行会自动包含到字符串中,如果不想包含,在行尾添加一个 \
即可。如下例:
1 | print("""\ |
将产生如下输出(注意最开始的换行没有包括进来):
1 | Usage: thingy [OPTIONS] |
字符串可以用 +
进行连接(粘到一起),也可以用 *
进行重复:
1 | # 3 times 'un', followed by 'ium' |
相邻的两个或多个 字符串字面值 (引号引起来的字符)将会自动连接到一起.
1 | 'Py' 'thon' |
把很长的字符串拆开分别输入的时候尤其有用:
1 | 'Put several strings within parentheses ' text = ( |
如果你想连接变量,或者连接变量和字面值,可以用 +
号:
1 | 'thon' prefix + |
字符串是可以被 索引 (下标访问)的,第一个字符索引是 0。单个字符并没有特殊的类型,只是一个长度为一的字符串:
1 | 'Python' word = |
1.4.2 常用方法
keywords | function |
---|---|
str.strip() |
删除开头和结尾的空白字符 |
str.lower(), str.upper() |
返回小写,大写的字符串 |
str1.replace(str2) |
用str2 替换str1 |
str.split(",") |
以分隔符为界将字符串拆成子串 |
in, not in |
检查是否在字符串内 |
+ |
串联字符串 |
str.format() |
格式化组合字符串,很好地替代了printf() >>>"The sum of 1 + 2 is {0}".format(1+2) 'The sum of 1 + 2 is 3' |
2 函数
2.1 一个简单的Fibonacci数列函数
1 | def fib2(n): # return Fibonacci series up to n |
2.2 默认值参数
最有用的形式是对一个或多个参数指定一个默认值。这样创建的函数,可以用比定义时允许的更少的参数调用,比如:
1 | def ask_ok(prompt, retries=4, reminder='Please try again!'): |
这个函数可以通过几种方式调用:
- 只给出必需的参数:
ask_ok('Do you really want to quit?')
- 给出一个可选的参数:
ask_ok('OK to overwrite the file?', 2)
- 或者给出所有的参数:
ask_ok('OK to overwrite the file?', 2, 'Come on, only yes or no!')
这个示例还介绍了 in
关键字。它可以测试一个序列是否包含某个值。
默认值是在 定义过程 中在函数定义处计算的,所以
1 | i = 5 |
会打印 5
。
重要警告: 默认值只会执行一次。这条规则在默认值为可变对象(列表、字典以及大多数类实例)时很重要。比如,下面的函数会存储在后续调用中传递给它的参数:
1 | def f(a, L=[]): |
这将打印出
1 | [1] |
如果你不想要在后续调用之间共享默认值,你可以这样写这个函数:
1 | def f(a, L=None): |
2.3 关键字参数
也可以使用形如 kwarg=value
的 关键字参数 来调用函数。例如下面的函数:
1 | def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'): |
接受一个必需的参数(voltage
)和三个可选的参数(state
, action
,和 type
)。这个函数可以通过下面的任何一种方式调用:
1 | parrot(1000) # 1 positional argument |
但下面的函数调用都是无效的:
1 | parrot() # required argument missing |
3 语法糖||特性
3.1 lambda表达式
可以用 lambda
关键字来创建一个小的匿名函数。这个函数返回两个参数的和: lambda a, b: a+b
。Lambda函数可以在需要函数对象的任何地方使用。它们在语法上限于单个表达式。从语义上来说,它们只是正常函数定义的语法糖。与嵌套函数定义一样,lambda函数可以引用所包含域的变量:
1 | def make_incrementor(n): |
上面的例子使用一个lambda表达式来返回一个函数。另一个用法是传递一个小函数作为参数:
1 | 1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')] pairs = [( |
3.2 列表生成式 list comprehensions
列表生成式即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式。
举个例子,要生成list
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
可以用list(range(1, 11))
:1
2list(range(1, 11))
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]但如果要生成
[1x1, 2x2, 3x3, ..., 10x10]
怎么做?1
2for x in range(1, 11)] [x * x
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]写列表生成式时,把要生成的元素
x * x
放到前面,后面跟for
循环,就可以把list创建出来,十分有用,多写几次,很快就可以熟悉这种语法。for循环后面还可以加上if判断,这样我们就可以筛选出仅偶数的平方:
1
2for x in range(1, 11) if x % 2 == 0] [x * x
[4, 16, 36, 64, 100]还可以使用两层循环,可以生成全排列:
1
2for m in 'ABC' for n in 'XYZ'] [m + n
['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']三层和三层以上的循环就很少用到了。
运用列表生成式,可以写出非常简洁的代码。例如,列出当前目录下的所有文件和目录名,可以通过一行代码实现:
1
2
3import os # 导入os模块,模块的概念后面讲到
for d in os.listdir('.')] # os.listdir可以列出文件和目录 [d
['.emacs.d', '.ssh', '.Trash', 'Adlm', 'Applications', 'Desktop', 'Documents', 'Downloads', 'Library', 'Movies', 'Music', 'Pictures', 'Public', 'VirtualBox VMs', 'Workspace', 'XCode']
3.1 生成器 generator
1. 生成器定义
在Python中,一边循环一边计算的机制,称为生成器:generator。
2. 为什么要有生成器
列表所有数据都在内存中,如果有海量数据的话将会非常耗内存。
如:仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
如果列表元素按照某种算法推算出来,那我们就可以在循环的过程中不断推算出后续的元素,这样就不必创建完整的list,从而节省大量的空间。
简单一句话:我又想要得到庞大的数据,又想让它占用空间少,那就用生成器!
3. 如何创建生成器
第一种方法很简单,只要把一个列表生成式的[]
改成()
,就创建了一个generator:
1 | for x in range(10)] L = [x * x |
方法二, 如果一个函数中包含yield
关键字,那么这个函数就不再是一个普通函数,而是一个generator。调用函数就是创建了一个生成器(generator)对象。
4. 生成器的工作原理
(1)生成器(generator)能够迭代的关键是它有一个next()方法,
工作原理就是通过重复调用next()方法,直到捕获一个异常。
(2)带有 yield 的函数不再是一个普通函数,而是一个生成器generator。
可用next()调用生成器对象来取值。next 两种方式 t.next() | next(t)。
可用for 循环获取返回值(每执行一次,取生成器里面一个值)
(基本上不会用next()
来获取下一个返回值,而是直接使用for
循环来迭代)。
(3)yield相当于 return 返回一个值,并且记住这个返回的位置,下次迭代时,代码从yield的下一条语句开始执行。
(4).send() 和next()一样,都能让生成器继续往下走一步(下次遇到yield停),但send()能传一个值,这个值作为yield表达式整体的结果
——换句话说,就是send可以强行修改上一个yield表达式值。比如函数中有一个yield赋值,a = yield 5,第一次迭代到这里会返回5,a还没有赋值。第二次迭代时,使用.send(10),那么,就是强行修改yield 5表达式的值为10,本来是5的,那么a=10
感受下yield返回值的过程(关注点:每次停在哪,下次又开始在哪)及send()传参的通讯过程,
思考None是如何产生的(第一次取值:yield 返回了 i 值 0,停在yield i,temp没赋到值。第二次取值,开始在print,temp没被赋值,故打印None,i加1,继续while判断,yield 返回了 i 值 1,停在yield i):
总结:
什么是生成器?
生成器仅仅保存了一套生成数值的算法,并且没有让这个算法现在就开始执行,而是我什么时候调它,它什么时候开始计算一个新的值,并给你返回。
补充
*<generator>
可以将一个generator变为元组处理
4 IO流
n 文件操作
keywords | function |
---|---|
open() |
|
read() |
|
readline() |
|
readlines() |
|
write() |
|
close() |