跟着廖雪峰老师的Python教程学习Python3,遇到需要注意的地方写到这里,方便以后查阅总结,温故知新。感谢廖雪峰老师!
基础
Python中不限定数值大小
除法: / 普通除法,浮点型, // 取整数部分, % 取余
Python提供了==ord()==函数获取字符的整数表示,==chr()==函数把编码转换为对应的字符
Python的字符串类型是str, 以字节为单位的bytes, 用 b'abc' 表示,读取字节流需要用bytes
编码encode():
'ABC'.encode('ascii') = b'ABC'
,'中文'.encode('utf-8')
解码decode():
b'ABC'.decode('ascii') = 'ABC'
计算str包含多少个字符,可以用len()函数,
len('abc') = 3
-
一般加这两行,说明使用python3,编码方式是utf-8
#!/usr/bin/env python3 # -*- coding: utf-8 -*-
占位符:%d 整数,%f 浮点数,%s 字符串,%x 十六进制整数,%% 转义 %,%.2f 保留2为小数
list:l = [1, 2, 3, 'a'], 不同类型的元素也可以放到一个list里, 可操作的函数:append() = add(), insert(index, value), extend(list) = addAll(), count() = size(), clear(), copy(), pop(value), remove(index), reverse(), sort() ...
tuple: t = (1, 2, 4), 不可变list, 当有一个元素是 t = (1,) 用 , 区分
条件判断:if, elif, else
循环:
for x in ...:
,while boolean:
生成序列:
range(5)
, 转换成list/tuple:list/tuple(range(5))
字典:dict = {'a': 1, 'b': 2}, 相当于Java的Map, dict的key必须是不可变对象, 可操作函数:setdefault(), get(), clear(), copy() ...
集合:set:s = set([1, 2, 3]) / s = {1, 2, 3}, 相当于Java的Set, add(), remove(), & 交集, | 并集
函数
Python的内置函数 (注意函数名不要与内置函数重名)
定义函数:def,空函数:pass
判断类型:isinstance(x, A_tuple), 判断实例:issubclass(x, A_tuple)
-
函数可以返回多个值,但本质上是返回一个tuple!(例子中的 angel=0 表示默认值,必选参数在前,默认参数在后,默认参数必须指向不变对象!)
import math def move(x, y, step, angle=0): nx = x + step * math.cos(angle) ny = y + step * math.sin(angle) return nx, ny r = move(100, 100, 50, 30) print(r)
-
可变参数:
def calc(*nums): pass
, 在参数前加个星号,即表示为可变参数,0-n都可以,如果想传入list 或者 tuple,可以把在变量钱加个星号转换成可变数组:nums = [1, 2, 3] print(calc(*nums))
关键字函数:
**kw
: 入参是dict,好处是可以控制参数的传入命名关键字参数:
def person(name, age, *, city, job):
,用星号分隔,后面的视为命名关键字函数,可以有默认值。调用时必须传入key:city=HangZhou
五种参数类型的定义顺序:必选参数、默认参数、可变参数、命名关键字参数和关键字参数,
def f1(a, b, c=0, *args, **kw): pass
-
任意函数都可以通过:
fun(*args, **kw)
调用,无论参数如何定义,-
*args
是可变参数,args接收的是一个tuple -
**kw
是关键字参数,kw接收的是一个dict - 命名的关键字参数是为了限制调用者可以传入的参数名,同时可以提供默认值
- 定义命名的关键字参数在没有可变参数的情况下不要忘了写分隔符*,否则定义的将是位置参数
-
高级特性
切片(Slice):L是个list:
L[0:3]
,L[:3]
0 可省略,L[:10:2]
取前10个数,步长为2,L[:]
复制一个L. tuple, str等都可以切片迭代:迭代dict的key:
for key in d
, 迭代dict的value:for value in d.values()
, 同时迭代dict:for k, v in d.items()
, 字符串也可以迭代,通过isinstance('abc', Iterable)
判断是否可以迭代。多个变量也可迭代:
for x, y in [(1, 1), (2, 4), (3, 9)]: pring(x, y)
, Python内置的enumerate函数可以把一个list变成索引-元素对, 这样就可以在for循环中同时迭代索引和元素本身列表生成式:写列表生成式时,把要生成的元素x * x放到前面,后面跟for循环,
[x * x for x in range(1, 11)]
, 还可以跟 if 判断,还可再跟 for 循环,[m + n for m in 'ABC' for n in 'XYZ']
, 注意是方括号,如果是小括号就是生成器了-
生成器(generator):如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator, yield相当于print,但是每遇到yield就会中断
杨辉三角形:def triangles(): row = [1] while True: yield row row = [1] + [row[i] + row[i + 1] for i in range(0, len(row) - 1)] + [1] n = 0 for t in triangles(): print(t) n += 1 if n == 10: break
-
迭代器:注意区分Iterable和Iterator
- Iterable: 可直接作用于for循环的
- Iterator: 可以被next()函数调用并不断返回下一个值的对象,直到没有对象时抛出StopIteration错误
generator都是 Iterator 对象,但 list,dict,str虽然是 Iterable,却不是Iterator
使用iter()函数,可以把Iterable变成Iterator。Iterator是一个数据流,惰性计算,所以可以表示无限大的数据流。
for循环的本质就是不断调用next()函数实现的
函数式编程
-
高阶函数:变量可以指向函数
f = abs
,函数名是什么呢? 函数名其实就是指向函数的变量。编写高阶函数,就是让函数的参数能够接收别的函数。def wtf(a, b, f): return f(a) + f(b) print(wtf(-1, 2, abs))
高阶函数举例:
- map:map(f, Iterable) 接收两个参数,函数和Iterable, map将函数作用于每一个元素,并返回一个Iterator。Iterator是惰性的,可以通过list()把整个结果计算出来,并返回一个list
- reduce:reduce把一个函数作用在一个序列[x1, x2, x3, ...]上,取前两个元素算出的结果与下一个元素继续计算, 就像这样:
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
- filter:filter()也接收一个函数和一个序列。filter把函数作用于序列,返回True保该留元素,False丢弃该元素。同样也返回一个Iterator 惰性序列。
例如序列中的空字符串删掉:
list(filter(lambda s: s and s.strip(), ['A', '', 'B', None, 'C', ' '])) # 结果: ['A', 'B', 'C']
- sorted:对数字,按大小asc排序,对字符串,ASCII码排序, 例如:
sorted([36, 5, -12, 9, -21], key=abs)
,还可以传入func和是否反转:sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True)
-
返回函数:高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回。
像这样:当调用lazy_sum()时,并没有返回结果,而是返回了sum函数(变量),再次调用会返回一个新函数!每次的调用结果互不影响!def lazy_sum(*args): def sum(): ax = 0 for n in args: ax = ax + n return ax return sum
闭包:返回闭包时牢记的一点就是:返回函数不要引用任何循环变量,或者后续会发生变化的变量。
因为返回一个函数时,该函数并未执行!所以不要引用可能会变化的变量 匿名函数:lambda表达式
lambda x: x * x
-
装饰器(Decorator):在代码运行期间动态增加功能的方式,称为装饰器。本质上decorator就是一个返回函数的高阶函数。如果需要给decorator传入参数,则需要编写一个返回decorator的高阶函数。一个完整的decorator如下:注意:装饰器不能改变原函数的行为
import functools def log(func): @functools.wraps(func) ##@functools.wraps(func) 是为了保证装饰器不会对装饰器函数造成影响 def wrapper(*args, **kw): print('call %s():' % func.__name__) return func(*args, **kw) return wrapper
带参数的decorator:
import functools def log(text): def decorator(func): @functools.wraps(func) def wrapper(*args, **kw): print('%s %s():' % (text, func.__name__)) return func(*args, **kw) return wrapper return decorator
函数如果没有显示的return,则会return None
偏函数:functools模块提供的一个功能,例如:
int2 = functools.partial(int, base=2)
这样调用int2时,base默认就是2了,不用再传一遍,当然也可以传其他值,更灵活。偏函数可以接收函数对象,*args, **kw这三个参数。
模块
Python中一个.py文件就是一个模块(module). Python中有包(package)的概念,每个包下必须要有__init__.py
文件,用于区分普通目录与Python的包。 __init__.py
也是一个模块,它的模块名是包的名称。 包可以有多级。注意创建的模块名不要与Python自带的模块名冲突,否则无法导入自带模块,比如 sys
模块。
-
使用模块:
import sys
之后就可以使用 sys 提供的功能了。例如
sys.argv
, sys的argv变量,用list存储了命令行的所有参数,argv至少有一个元素,就是文件名称。
其他注意的地方:- 任何模块代码的第一个字符串都被视为模块的文档注释
- 使用author 把模块作者写进去,
__author__ = 'DreamYoung'
- 命令行运行测试:
if __name__ = '__main__'
- 作用域:
__xxx__
是特殊变量,一般不要用这种变量名,模块的文档注释可以用__doc__
访问,__xx
是private函数或变量,不应该被外部模块直接引用(Python并没有限制),其他函数或变量为public。注意封装与抽象。
-
安装第三方模块:通过包管理工具pip完成,由于是Python3,应该使用pip3,比如安装处理图像的工具库Pillow:
pip3 install Pillow
(Python解释器搜索模块路径放到sys.path
变量中,如果找不到可以设置下环境变量PYTHONPATH
)其他常用模块:
- MySQL的驱动
mysql-connector-python
, - 科学计算的NumPy库
numpy
- 生成文本的模板工具
Jinja2
- MySQL的驱动