跟学廖雪峰python教程新学新知
廖雪峰python教程新学新知
python基础
-
r''表示''内部的字符串默认不转义。 -
ord()函数获取字符的整数表示,chr()函数把编码转换为对应的字符。 -
bytes类型的数据用带b前缀的单引号或双引号表示:
x = b'ABC'。 -
encode('编码类型')方法可以编码为指定的bytes,decode('编码类型')方法将bytes转换为str。 -
decode('编码类型', errors='ignore')中,传入errors='ignore'忽略错误的字节。 -
保存文件时指定编码类型以及增加运行头文件。
#!/usr/bin/env python3 # -*- coding: utf-8 -*- -
输出格式化有三种方法:
- % 运算符 :同c语言
>>> 'Hello, %s' % 'world' 'Hello, world' >>> 'Hi, %s, you have $%d.' % ('Michael', 1000000) 'Hi, Michael, you have $1000000.'- format函数 :传入的参数依次替换字符串内的占位符{0}、{1}……
>>> 'Hello, {0}, 成绩提升了 {1:.1f}%'.format('小明', 17.125) 'Hello, 小明, 成绩提升了 17.1%'- f-string
小明的成绩从去年的72分提升到了今年的85分,请计算小明成绩提升的百分点,并用字符串格式化显示出
'xx.x%',只保留小数点后1位:s1 = 72 s2 = 85 r = (s2-s1)/s1 print('%004.1f%%' % r) -
tuple元素不可变,但tuple中的list可变。
-
模式匹配可匹配复杂语句和列表。
age = 15 match age: case x if x < 10: print(f'< 10 years old: {x}') case 10: print('10 years old.') case 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18: print('11~18 years old.') case 19: print('19 years old.') case _: print('not sure.') args = ['gcc', 'hello.c', 'world.c'] # args = ['clean'] # args = ['gcc'] match args: # 如果仅出现gcc,报错: case ['gcc']: print('gcc: missing source file(s).') # 出现gcc,且至少指定了一个文件: case ['gcc', file1, *files]: print('gcc compile: ' + file1 + ', ' + ', '.join(files)) # 仅出现clean: case ['clean']: print('clean') case _: print('invalid command.')
函数
-
hex()函数转换16进制。
-
函数名是一个指向函数对象的引用,可以把函数赋给一个变量。
-
函数返回值是一个单一值,当有多个值返回时,实际上是返回一个tuple。
-
默认参数必须指向不变对象。
def add_end(L=[]): L.append('END') return L >>> add_end([1, 2, 3]) [1, 2, 3, 'END'] >>> add_end() ['END'] >>> add_end() ['END', 'END']修改后
def add_end(L=None): if L is None: L = [] L.append('END') return L >>> add_end() ['END'] >>> add_end() ['END'] -
可变参数
*argv,可传入数量是任意的,在list或tuple前面加一个*号,把list或tuple的元素变成可变参数传进去。 -
关键字参数
**kw,传入的是dict内容,**dict可以将dict中内容传入函数,同时**kw获得的参数则是**dict的一份拷贝。 -
命名关键词参数特殊分隔符
*,*后面的参数被视为命名关键字参数。其作用是限制关键字参数。def person(name, age, *, city, job): print(name, age, city, job)如果函数定义中已经有了一个可变参数,后面的命名关键字参数就不再需要一个特殊分隔符
*了。def person(name, age, *args, city, job): print(name, age, args, city, job) -
定义函数可以组合使用这5种参数:必选参数、默认参数、可变参数、关键字参数和命名关键字参数。
参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数。 -
对于任意函数,都可以通过类似
func(*args, **kw)的形式调用它,无论它的参数是如何定义的。 -
对于递归来说,不需要展开思考的它的中间过程,这违背了递归的初心。
按照递归的思路,只需要考虑n和n-1的关系就好,至于n-2,n-3...完全没必要考虑。
高级特性
-
代码越少,开发效率越高。
-
enumerate函数可以把一个list变成 索引-元素 对。 -
在一个列表生成式中,
for前面的if ... else是表达式(所以必须有else),而for后面的if是过滤条件,不能带else。>>> [x for x in range(1, 11) if x % 2 == 0] [2, 4, 6, 8, 10] >>> [x if x % 2 == 0 else -x for x in range(1, 11)] [-1, 2, -3, 4, -5, 6, -7, 8, -9, 10] -
创建一个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 0x1022ef630> -
如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator函数,调用一个generator函数将返回一个generator。
def fib(max): n, a, b = 0, 0, 1 while n < max: yield b a, b = b, a + b n = n + 1 return 'done' >>> f = fib(6) >>> f <generator object fib at 0x104feaaa0>
-
-
generator函数和普通函数的执行流程不一样。
普通函数是顺序执行,遇到return语句或者最后一行函数语句就返回。
而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。def odd(): print('step 1') yield 1 print('step 2') yield(3) print('step 3') yield(5) >>> o = odd() >>> next(o) step 1 1 >>> next(o) step 2 3 >>> next(o) step 3 5 >>> next(o) Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration -
调用generator函数会创建一个generator对象,多次调用generator函数会创建多个相互独立的generator。
接上 >>> next(odd()) step 1 1 >>> next(odd()) step 1 1 >>> next(odd()) step 1 1 -
解杨辉三角,有三种解法(至少会一种,且理解第一种解法):
def triangles(): L = [1] while True: yield L L = [sum(i) for i in zip([0]+L, L+[0])] def triangles(): ret = [1] while True: yield ret for i in range(1, len(ret)): ret[i] = pre[i] + pre[i - 1] ret.append(1) pre = ret[:] def YangHui (num = 10): LL = [[1]] for i in range(1,num): LL.append([(0 if j== 0 else LL[i-1][j-1])+ (0 if j ==len(LL[i-1]) else LL[i-1][j]) for j in range(i+1)]) return LL -
通函数调用直接返回结果:
>>> r = abs(6) >>> r 6generator函数的调用实际返回一个generator对象:
>>> g = fib(6) >>> g <generator object fib at 0x1022ef948>一般用for循环来调用generator:
>>> g = (x * x for x in range(10)) >>> for n in g: ... print(n) >>> for n in fib(6): ... print(n) -
可以直接作用于
for循环的对象统称为可迭代对象:Iterable, 包括集合数据类型、generator
可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator -
可以用
isinstance()函数判断是否是Iterable或Iterator。 -
生成器都是
Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator。 -
Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。
Iterator甚至可以表示一个无限大的数据流,如全体自然数。
总结:-
凡是可作用于for循环的对象都是Iterable类型;
-
凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;
-
集合数据类型是Iterable但不是Iterator,可以通过iter()函数获得一个Iterator对象。
-
函数式编程
-
一个函数可以接收另一个函数作为参数,这种函数称之为高阶函数。
def add(x, y, f): return f(x) + f(y) 推导过程: x = -5 y = 6 f = abs f(x) + f(y) ==> abs(-5) + abs(6) ==> 11 return 11 -
map(f,Iterable)函数接受两个参数,一个是函数f,一个是Iterable。
作用是将函数f作用到Iterable中的每个元素上,返回类型是Iterator。 -
reduce(g,Iterable)函数接受两个参数,一个是函数g,一个是Iterable。
作用是将函数g作用到Iterable中的每个元素上并把结果继续和序列的下一个元素做累积计算,返回类型是Iterator。reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4) -
filter(h,Iterable)函数接受两个参数,一个是函数h,一个是Iterable。
作用是将函数f作用到Iterable中的每个元素上,然后根据返回值是True还是False决定保留还是丢弃该元素。返回类型是Iterator。 -
filter()函数应用于求素数的埃氏筛法。def _odd_iter(): n = 1 while True: n = n + 2 yield n def _not_divisible(n): return lambda x: x % n > 0 def primes(): yield 2 it = _odd_iter() # 初始序列 while True: n = next(it) # 返回序列的第一个数 yield n it = filter(_not_divisible(n), it) # 构造新序列 -
sorted()函数也是一个高阶函数,它还可以接收一个key函数来实现自定义的排序。>>> sorted([36, 5, -12, 9, -21], key=abs) [5, 9, -12, -21, 36] -
返回函数,把函数作为一个函数的返回值。
def lazy_sum(*args): def sum(): ax = 0 for n in args: ax = ax + n return ax return sum >>> f = lazy_sum(1, 3, 5, 7, 9) >>> f <function lazy_sum.<locals>.sum at 0x101c6ed90> >>> f() 25 -
调用lazy_sum()时,每次调用都会返回一个新的函数,即使传入相同的参数。