Python - 学习笔记
一、基础笔记
列表:list
用 len()
函数可以获得 list
元素的个数:
1 | len(classmates) |
list
是一个可变的有序表,所以,可以往 list
中追加元素到末尾:
1 | 'Adam') classmates.append( |
要删除 list
末尾的元素,用 pop()
方法。要删除指定位置的元素,用 pop(i)
方法,其中 i 是索引位置。
循环:for 和 while
for 循环:range()
函数,可以生成一个整数序列,再通过 list()
函数可以转换为list。
while 循环:continue
语句,跳过当前的这次循环,直接开始下一次循环。break
语句可以提前退出循环。
dict
通过 in
判断 key
是否存在:
1 | 'Thomas' in d |
通过 dict
提供的 get()
方法,如果 key
不存在,可以返回 None
,或者自己指定的 value
:
1 | 'Thomas') d.get( |
要删除一个 key
,用 pop(key)
方法,对应的 value
也会从 dict
中删除:
1 | 'Bob') d.pop( |
set
set
和 dict
类似,也是一组 key
的集合,但不存储 value
。由于 key
不能重复,所以,在 set
中,没有重复的 key
。
通过 add(key)
方法可以添加元素到 set
中,可以重复添加,但不会有效果,通过 remove(key)
方法可以删除元素。
参数组合
在 Python
中定义函数,可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,这5种参数都可以组合使用。但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数。
切片
取前 3 个元素,用一行代码就可以完成切片:
1 | 0:3] L[ |
Python
支持 L[-1]
取倒数第一个元素,那么它同样支持倒数切片,试试:
1 | 2:] L[- |
所有数,每5个取一个:
1 | 5] L[:: |
列表生成式
列表生成式即 List Comprehensions,是 Python
内置的非常简单却强大的可以用来创建 list
的生成式。
举个例子,要生成 list [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]可以用 list(range(1, 11))
:
1 | list(range(1, 11)) |
但如果要生成[1x1, 2x2, 3x3, …, 10x10]怎么做?方法一是循环:
1 | L = [] |
但是循环太繁琐,而列表生成式则可以用一行语句代替循环生成上面的 list
:
1 | for x in range(1, 11)] [x * x |
写列表生成式时,把要生成的元素x * x放到前面,后面跟for循环,就可以把list创建出来,十分有用,多写几次,很快就可以熟悉这种语法。
for循环后面还可以加上if判断,这样我们就可以筛选出仅偶数的平方:
1 | for x in range(1, 11) if x % 2 == 0] [x * x |
还可以使用两层循环,可以生成全排列:
1 | for m in 'ABC' for n in 'XYZ'] [m + n |
二、函数式编程
map
函数:接收一个函数和一个序列,并把传入的函数作用于每个元素
reduce
函数:把一个函数作用在一个序列[x1, x2, x3, …]上,这个函数必须接收两个参数,reduce
把结果继续和序列的下一个元素做累积计算,其效果就是:
1 | reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4) |
fiter
函数:和 map
类似,区别是会根据返回值是 True
和 False
决定保留还是丢弃该元素
sorted
函数:排序函数,可通过key实现自定义排序。可传入第三个参数 reverse=True
,要进行反向排序,不必改动 key
函数。
1 | sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True) |
匿名函数:lambda x: x * x实际上就是:
1
2def f(x):
return x * x
关键字 lambda
表示匿名函数,冒号前面的 x
表示函数参数。
装饰器——?:需要再进一步了解。
偏函数:functools.partial
就是帮助我们创建一个偏函数的,不需要我们自己定义 int2()
,可以直接使用下面的代码创建一个新的函数 int2
:
1 | import functools |
- 定义:对原函数的默认参数进行改造,为我所用
- 方式:
max8=functools.partial(max,8)
(当然要先导入functools
包) - 新知:
int
居然这么强,int('1234234',2)
三、调试
程序能一次写完并正常运行的概率很小,基本不超过 1%。总会有各种各样的 bug
需要修正。有的 bug
很简单,看看错误信息就知道,有的 bug
很复杂,我们需要知道出错时,哪些变量的值是正确的,哪些变量的值是错误的,因此,需要一整套调试程序的手段来修复 bug
。
第一种方法简单直接粗暴有效,就是用 print()
把可能有问题的变量打印出来看看:
1 | def foo(s): |
执行后在输出中查找打印的变量值:
1 | $ python ~/documents/err.py |
用 print()
最大的坏处是将来还得删掉它,想想程序里到处都是 print()
,运行结果也会包含很多垃圾信息。所以,我们又有第二种方法。
断言
凡是用 print()
来辅助查看的地方,都可以用断言(assert)来替代:
1 | def foo(s): |
assert
的意思是,表达式 n != 0
应该是 True
,否则,根据程序运行的逻辑,后面的代码肯定会出错。
如果断言失败,assert
语句本身就会抛出
1 | AssertionError: |
程序中如果到处充斥着 assert
,和 print()
相比也好不到哪去。不过,启动 Python
解释器时可以用 -O 参数来关闭assert
:
1 | $ python -O err.py |
关闭后,你可以把所有的 assert
语句当成pass
来看。
logging
把 print()
替换为 logging
是第3种方式,和 assert
比,logging
不会抛出错误,而且可以输出到文件:
1 | import logging |
logging.info()
就可以输出一段文本。运行,发现除了 ZeroDivisionError
,没有任何信息。怎么回事?
别急,在 import logging
之后添加一行配置再试试:
1 | import logging |
看到输出了:
1 | $ python err.py |
这就是 logging
的好处,它允许你指定记录信息的级别,有 debug
,info
,warning
,error
等几个级别,当我们指定 level=INFO
时,logging.debug
就不起作用了。同理,指定 level=WARNING
后,debug
和 info
就不起作用了。这样一来,你可以放心地输出不同级别的信息,也不用删除,最后统一控制输出哪个级别的信息。logging
的另一个好处是通过简单的配置,一条语句可以同时输出到不同的地方,比如console
和文件。
pdb
第4种方式是启动 Python
的调试器 pdb
,让程序以单步方式运行,可以随时查看运行状态。我们先准备好程序:
1 | s = '0' |
然后启动:
1 | $ python -m pdb err.py |
以参数 -m pdb
启动后,pdb
定位到下一步要执行的代码-> s = '0'
。输入命令 l
来查看代码:
1 | (Pdb) l |
输入命令n可以单步执行代码:
1 | (Pdb) n |
任何时候都可以输入命令p 变量名来查看变量:
1 | (Pdb) p s |
输入命令q结束调试,退出程序:
1 | (Pdb) q |
这种通过 pdb
在命令行调试的方法理论上是万能的,但实在是太麻烦了,如果有一千行代码,要运行到第 999 行得敲多少命令啊。还好,我们还有另一种调试方法。
1 | pdb.set_trace() |
这个方法也是用 pdb
,但是不需要单步执行,我们只需要 import pdb
,然后,在可能出错的地方放一个 pdb.set_trace()
,就可以设置一个断点:
1 | import pdb |
运行代码,程序会自动在 pdb.set_trace()
暂停并进入 pdb
调试环境,可以用命令 p
查看变量,或者用命令 c
继续运行:
1 | $ python err.py |
这个方式比直接启动 pdb
单步调试效率要高很多,但也高不到哪去。
IDE
如果要比较爽地设置断点、单步执行,就需要一个支持调试功能的 IDE
。目前比较好的 Python IDE
有:
Visual Studio Code:需要安装Python
插件。
PyCharm。
另外,Eclipse
加上 pydev
插件也可以调试 Python
程序。
小结:写程序最痛苦的事情莫过于调试,程序往往会以你意想不到的流程来运行,你期待执行的语句其实根本没有执行,这时候,就需要调试了。
虽然用 IDE
调试起来比较方便,但是最后你会发现,logging
才是终极武器。