使用MarkDown学习Python。(前面基础的都在XMind)
进制转换
- 转成十进制(一般是二进制,八进制,十六进制):
所有转成十进制的,都只需要int(原数字的字符串格式,进制数)a = "1001"
s = int(a,2)这个就是把二进制的数字a转成十进制
print(s) - 十进制转十六进制(使用函数hex())
print(hex(1033))
0x409 - 十进制转二进制(使用函数bin())
print(bin(10))
0b1010 - 十进制转八进制(使用函数oct())
print(oct(100))
0o144
函数
主要难的是递归函数
递归函数就是在函数里调用自身函数
例:计算阶乘n!,用函数fact(n)表示
fact(n)=n!=n×(n-1)×(n-2)×(n-3)×······3×2×1
所以fact(n)=n×fact(n-1),当n=1的时候特殊处理
def fact(n):
if n == 1:
return 1
return n*fact(n-1)
递归的两个重要因素:终止条件 和 调用函数里的表达式
当里面被调用的函数表达式一直减到终止条件,应该return值。
递归为了解决栈的存储问题,有一个尾递归优化方法:尾递归是指,在函数返回的时候,调用自身本身,并且,return语句不能包含表达式。这样,编译器或者解释器就可以把尾递归做优化,使递归本身无论调用多少次,都只占用一个栈帧,不会出现栈溢出的情况。
def fact(n):
return fact_iter(n, 1)
def fact_iter(num, product):
if num == 1:
return product
return fact_iter(num - 1, num * product)
这个尾递归的优化方法等熟练递归之后再使用吧
求斐波那契数列:
def fab(n):
if n == 1 or n == 2:
return 1
return fab(n-1)+fab(n-2)
print(fab(7))
#结果是13
函数的参数
函数的参数分为五种:必选参数,位置参数,可变参数(*args),命名关键字参数,关键字参数(**kw)。
- 必选参数:必须得要输入的参数
- 非必填项,在定义函数的时候,就给了一个默认的值,你不输入的话,就默认为这个数值
- 可变参数 *args :可变参数就是传入的参数个数是可变的,可以是1个、2个到任意个,还可以是0个。允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple。
- 关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个字典,调用函数的时候里面写fun('A'='a','B'='b')
迭代
迭代里的enumerate(list)函数会返回一个一一对应索引跟列表元素的enumerate对象。
enumerate函数还可以接收第二个参数,用来表示索引的起始位置。
补充一个isinstance函数,isinstance(obj,数据类型(可以是int,也可以是容器list等))
生成器(generator)
相关文章链接
生成器的写法跟列表解析式差不多,只是外面一个是小括号一个是中括号。但是使用列表解析式创建出来的是一个可以直接使用的列表容器。
generator保存的是算法,每次调用next(g),就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。
创建出来的生成器想要打印生成器里的元素,需要调用next()函数来一个一个打印生成器里的元素,一般next(g),就可以了,但是这样效率太低,不如使用for循环,next()函数一般不咋用,有for循环就够了。
for i in g:
print(i)
如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator函数。
def odd():
print('step 1')
yield 1
print('step 2')
yield(3)
print('step 3')
yield(5)
调用该generator函数时,首先要生成一个generator对象,然后用next()函数不断获得下一个返回值。
调用该generator函数时候,首先需要生成一个对象,就比如上面的那个odd()这个generator函数,首先o = odd(),生成一个对象,然后调用next(o)函数不断获取函数值。generator对象在执行过程中,遇到yield就中断,下次调用继续执行,当执行结果没有的时候就会报错。
报错类型是StopIteration
generator函数里的yield就相当于普通函数的return,可以在后面加返回值,没有就返回空,函数执行到yield就会返回。再次执行时从上次返回的yield语句处继续执行。
还有一个重点就是在使用for循环遍历生成器里面的元素时,如果这个函数会一直生成,就必须添加一个终止条件;如果这个生成器生成的元素有是有限的,就必须使用try-except来捕获StopIteration错误。
就记住生成器函数使用必须先生成一个对象,for循环里面记得终止条件或者错误捕获。
斐波那契数列函数改成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'
使用生成器将二维数组转换成一维数组
迭代器
可迭代对象iterable:容器类型的列表,元组,字典等,生成器generator和生成器函数。
迭代器iterator:可以被next()函数直接调用,并且不断返回下一个值的对象,生成器对象就是这样的。
但不管是可迭代对象还是迭代器都能直接使用for循环。
将可迭代对象(就是容器这些)转换成迭代器(就是能直接被next()函数调用的),可以使用iter()方法。
函数式编程
高阶函数:
就是一个函数里不仅能接受变量,也能接受其他函数名,然后在内部可以直接调用这个函数。例如map()函数,既能接收表达式,也能接受可迭代对象,然后把可迭代对象里的元素一个一个都经表达式运算,最后返回一个包含元素的map对象。
reduce()函数
reduce(函数x,序列l)函数接受俩参数,一个是表达式,一个是序列(容器list或者任何包含许多元素序列的对象)。然后要求函数x必须接受俩参数,(这两个参数来自后面的序列l),函数x对传入的两个参数运算,然后返回运算值,而reduce()函数会将返回的值作为一个元素,与序列l的下一个元素一起再传给函数x,这样reduce()函数就实现了累计的作用。就例如这样:
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
使用reduce()函数可以实现对一个列表的求和:
l = [1,2,3,4,5,6,7,8,9]
def add(x,y):
return x+y
reduce(add,l)
但是python有内置的函数sum()来对序列求和,但使用reduce()还有其他用处:将一个列表的str转成int,并合成一个数
def combine(x,y):
return x*10+y
reduce(combine,map(int,"123456789"))
课后练习题:
- 利用map()规范大小写,注意,map传入的函数里面不需要再传参数了,map会默认传入序列里的每个元素。
- 列表求积
- 利用map和reduce编写一个str2float函数,把字符串'123.456'转换成浮点数123.456:(当需要对字符转数字,而且需要map函数的时候,可以先这样创建一个字典的函数来转。这个答案是借鉴大佬的)
fitter()函数
一般用于筛掉一些序列里的元素。而且跟map一样,需要list里面的元素,不然返回的就是一个封装的fitter对象。
fitter()函数跟map()函数一样,接受一个函数x和一个序列,然后依次将序列里的元素一个一个作用在函数x里,函数x里的return需要返回 True或False。fitter()函数会根据函数x返回的True或是False来确定是否保留该函数。
找回文数字:传入的函数里面写判断条件
判断是不是回文数字只需要这两行代码:
def huiwen(n):
l = [i for i in str(n)]
return l == l[::-1]
返回函数(闭包)(还是不熟)
文档链接
在函数嵌套的前提下,内部函数使用了外部函数的变量,并且外部函数返回了内部函数,我们把这个使用外部函数变量的内部函数称为闭包。
引用B站大佬的评论,闭包的作用就是:在最后调用的时候,外部函数的生命周期会结束,但是外部函数还能用是因为闭包会在内存中开辟一个空间里面保存的内部函数还有外部函数定义的局部变量,就是会记住外部函数里的变量。
- 就是嵌套函数。
- 内部函数使用了外部函数的变量,还包括外部函数的参数。
- 外部函数return的是内部函数,不是结果。
有这三个条件的就构成闭包
# 定义一个函数
def fun_u(n1):
# 定义一个内部函数
def fun_in(n2):
# 内部函数使用了外部函数的变量
result = n1+n2
print("结果:", result)
return fun_in
# 创建闭包实列
f = fun_u(1) (f就是个内部函数的实例对象,可以理解就是个函数,因为返回的就是内部函数)
# 执行闭包
f(2) >>3
f(3) >>4
看的视频讲解是这样说的:当f(2)开始执行这个闭包的时候,会是这样的fun_u()(),内部函数先不运行,然后return内部函数,fun_u()就变成了fun_in,所以最后就变成fun_in()。
闭包的作用:闭包可以保存外部函数内的变量,不会随着外部函数调用完而销毁。同时也占用了内存。
def count():
fs = []
for i in range(1, 4):
def f():
return i*i
fs.append(f)
return fs
f1, f2, f3 = count()
结果都是9,并不是我想的是个列表,原因是这样,首先,内部函数不会按着顺序运行调用的,所以,f1()运行这个闭包的时候,先是外部函数count运行,但是内部的f()函数没有运行,for循环走完,然后i=3了,开始return了,这个时候内部函数f()开始运行,运行里面的i也就只是个三,于是最后返回的是9。
闭包这一块就记住,最后返回的是一个闭包,这个闭包里面是内部函数还有外部函数的变量,闭包是会记住外部函数变量的值,创建实例对象的时候主要是返回闭包,而真正代码运行的就是调用函数的时候。
匿名函数
匿名函数简单就记lambda 这写变量 :表达式
装饰器
先了解个简单函数,前面学的当一个函数被def之后,他的名字可以随便赋给一个变量,这个变量同样可以调用这个函数,函数对象有一个__name__属性,可以返回函数的名字
def fun():
pass
print("函数被调用了")
a = fun #这里不需要加括号
a() >>>结果同样会打印,这个就是函数名可以随便赋给一个变量
a.__name__ >>>会打印函数的名字fun,不加括号
现在开始装饰器
装饰器本质就是一个闭包,不过在内层函数里,会有传入的函数,闭包本来最低就有俩函数一个外层一个内层。装饰器就像一个时光屋,然后外面的顾客(不是闭包的,另一个函数)进来,这个顾客函数就有了时光屋的功能。
import time
#其实装饰器就是一个闭包,给传入的函数增添一项功能
#例如这段代码,就是给function函数增添一个计算消耗时间的功能
def out(function):
#这里需要传入一个函数,实例对象的时候只需要写函数名就行,
#不加括号,这个就是时间屋给顾客函数增添一个可以计时的功能。
def inner():
time_start = time.time()
function()
time_end = time.time()
print(f"函数{function.__name__}花费的时间{time_end-time_start:.6f}")
return inner
def function(): #这个就是顾客函数
for i in range(1000000):
pass
print("这是function函数")
function = out(function)
#这一步就是实例对象,只不过实例出的对象名字跟运行的函数名相同
#不相同也可以,这里相同只是为了方便后面语法糖的理解。
function()
也可以用一个@表达,这个就是语法糖
#还是上面那些代码
def out(function):
def inner():
time_start = time.time()
function()
time_end = time.time()
print(f"函数{function.__name__}花费的时间{time_end-time_start:.6f}")
return inner
@out #其实这句话就等价于function = out(function),只是创建实例对象,但不同是必须放在顾客函数后面。
def function():
for i in range(1000000):
pass
print("这是function函数")
#不过最后实例对象的时候不需要再function = out(function),这句话来实例对象了。必须放在顾客函数前面,一句@out(out是外部函数名)
#创建完语法糖之后可以直接调用顾客函数了。
function()
这样一个闭包就完成了一个装饰器的作用了。
还有一个就是,当顾客函数需要传入参数的时候,闭包的那个函数的内层函数负责传入顾客函数的参数,外层函数是负责传入顾客函数的。@out语法糖默认传入给外层函数就是下面的顾客函数,也可以@out()来传入参数,这个括号里面给的是最外层函数,这只是当闭包那个函数里面有多层嵌套的时候,其实最终传给顾客函数的参数不用管也不用在语法糖后面加括号。
还是太熟练,这一段还需要多看那个文档
经过内置装饰器装饰过的
记得wrapper这个返回原来函数名的包装
偏函数(这个不咋难了)
当函数的参数个数太多,需要简化时,使用functools.partial可以创建一个新的函数,这个新函数可以固定住原函数的部分参数,从而在调用时更简单。
就比如之前进制转换的int(10,2),这个的意思就是把二进制的数字10,转成十进制的数字,后面的这个2,其实就是int()函数自带的参数base。
可以使用functools模块的functools.partial来帮助我们创建一个偏函数。例如 这个都是把二进制的数字转成十进制,结果都是2。
import functools
def int2(x,y=2):
return int(x,y)
print(int2("10"))
int_2 = functools.partial(int,base=2)
print(int_2("10"))
标签:闭包,function,return,进阶,Python,参数,def,函数
From: https://www.cnblogs.com/huanc/p/17441377.html