高阶函数:接收函数作为参数,或者将函数作为返回值的函数
# 创建一个列表
l = [1,2,3,4,5,6,7,8,9,10]
# 定义一个函数,用来检查一个任意的数字是否是偶数
def fn2(i) :
if i % 2 == 0 :
return True
return False
def fn(func , lst) :
'''
fn()函数可以将指定列表中的所有偶数获取出来,并保存到一个新列表中返回
参数:
lst:要进行筛选的列表
'''
# 创建一个新列表
new_list = []
# 对列表进行筛选
for n in lst :
# 判断n的奇偶
if func(n) :
new_list.append(n)
if n > 5 :
new_list.append(n)
# 返回新列表
return new_list
print(fn(fn2,l)) # [2, 4, 6, 6, 7, 8, 8, 9, 10, 10]
lambda函数表达式专门用来创建一些简单的函数,是函数创建的又一种方式;
匿名函数一般都是作为参数使用,其他地方一般不会使用
语法:lambda 参数列表 : 返回值
fn6 = lambda a,b : a + b
print(fn6(10,30)) # 40
filter(func,l) 可以从序列中过滤出符合条件的元素,保存到一个新的序列中
参数:
1.函数,根据该函数来过滤序列(可迭代的结构)
2.需要过滤的序列(可迭代的结构)
返回值:
过滤后的新序列(可迭代的结构)
l = [1,2,3,4,5,6,7,8,9,10]
r = filter(lambda i : i > 5 , l)
print(list(r)) # [6, 7, 8, 9, 10]
map(func,l) 函数可以对对象中的所有元素做指定的操作,然后将其添加到一个新的对象中返回
l = [1,2,3,4,5,6,7,8,9,10]
r = map(lambda i : i ** 2 , l)
print(list(r)) # [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
123
python中的闭包从表现形式上定义(解释)为:
如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure).
比如说,如果你希望函数的每次执行结果,都是基于这个函数上次的运行结果。我以一个类似棋盘游戏的例子来说明。假设棋盘大小为50*50,左上角为坐标系原点(0,0),我需要一个函数,接收2个参数,分别为方向(direction),步长(step),该函数控制棋子的运动。棋子运动的新的坐标除了依赖于方向和步长以外,当然还要根据原来所处的坐标点,用闭包就可以保持住这个棋子原来所处的坐标。
origin = [0, 0] # 坐标系统原点
legal_x = [0, 50] # x轴方向的合法坐标
legal_y = [0, 50] # y轴方向的合法坐标
def create(pos=origin):
def player(direction,step):
# 这里应该首先判断参数direction,step的合法性,比如direction不能斜着走,step不能为负等
# 然后还要对新生成的x,y坐标的合法性进行判断处理,这里主要是想介绍闭包,就不详细写了。
new_x = pos[0] + direction[0]*step
new_y = pos[1] + direction[1]*step
pos[0] = new_x
pos[1] = new_y
#注意!此处不能写成 pos = [new_x, new_y],原因在上文有说过
return pos
return player
player = create() # 创建棋子player,起点为原点
print player([1,0],10) # 向x轴正方向移动10步
print player([0,1],20) # 向y轴正方向移动20步
print player([-1,0],10) # 向x轴负方向移动10步
持续添加数,求平均
def make_averager():
# 创建一个列表,用来保存数值
nums = []
# 创建一个函数,用来计算平均值
def averager(n) :
# 将n添加到列表中
nums.append(n)
# 求平均值
return sum(nums)/len(nums)
return averager
averager = make_averager()
print(averager(10)) # 10.0
print(averager(20)) # 15.0
print(averager(30)) # 20.0
print(averager(40)) # 25.0
这有点像一种类似配置功能的作用,我们可以修改外部的变量,闭包根据这个变量展现出不同的功能。比如有时我们需要对某些文件的特殊行进行分析,先要提取出这些特殊行。
def make_filter(keep):
def the_filter(file_name):
file = open(file_name)
lines = file.readlines()
file.close()
filter_doc = [i for i in lines if keep in i]
return filter_doc
return the_filter
如果我们需要取得文件"result.txt"中含有"pass"关键字的行,则可以这样使用例子程序
filter = make_filter("pass")
filter_result = filter("result.txt")
以上两种使用场景,用面向对象也是可以很简单的实现的,但是在用Python进行函数式编程时,闭包对数据的持久化以及按配置产生不同的功能,是很有帮助的。
记住:
1、python里面万物都是object
2、记住装饰器的等价形式
decorate直观不准确定义:不过是一个输入和输出都是函数的函数
def dec(f):
pass
@dec
def double(x):
return x**2
完全等价于:
double = dec(double)
注:输入一定是函数,输出则不一定,例如:
def dec(f):
return 1
@dec
def double(x):
return x**2
if __name__ == "__main__":
a=double
print(a)# a=1
# 原因是double = dec(double)
# dec return 1
# 因此此时double赋值为1
只是通常输出也是函数,关键在于最外层decorate return的东西
用于计时(内函数只执行一次)
import time
def timeit(f):
def wrapper(*args,**kwargs):
start=time.time()
result=f(*args, **kwargs)
end=time.time()
print("用时{:.2f}s".format(end-start))
return result
return wrapper
@timeit
def my_func(x):
time.sleep(x)
# 等价于my_func=timeit(my_func)
*args
,**kwargs
本质上就是为了允许接收变长的函数参数,以达到,不管我装饰什么样的函数,它都能用
除上述以外,可能还有带参数的decorate
实际上也很简单,比如
@timeit(10)
def double(x):
return x**2
# 等价于
double=timeit(10)(double)
即多了一次函数调用
import time
def timeit(iteration):
def inner(f):
def wrapper(*args,**kwargs):
start=time.time()
for _ in range(iteration):
result=f(*args, **kwargs)
end=time.time()
print("用时{:.2f}s".format(end-start))
return result
return wrapper
return inner
@timeit(1000)
def double(x):
return x**2
double(2)
本质是装饰器本身,也即装饰器本身既可以是类,也可以是函数
import time
class Timer:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
# 魔术函数__call__让所以这个类的实例都变得callable,也即这个类的对象都可以当作函数用
# 对象可以直接调用
start = time.time()
result = self.func(*args, **kwargs)
end = time.time()
print("用时{:.2f}s".format(end - start))
return result
@Timer
def add(a, b):
return a + b
# 等价于:add = Timer(add),将add这个函数转化为了一个Timer对象
result = add(2, 3)# add(Timer对象)使用了它的__call__函数
print(result)
跟函数装饰器的区别:
函数装饰器是 函数调用一个函数 返回一个函数,该函数是callable的
装饰器类是 类调用一个函数 返回一个对象 该对象是callable的
import time
class Timer:
def __init__(self, prefix):# 有改动
self.prefix = prefix# 有改动
def __call__(self, func):# 有改动
def wrapper(*args, **kwargs):# 有改动
# 魔术函数__call__让所以这个类的实例都变得callable,也即这个类的对象都可以当作函数用
# 对象可以直接调用
start = time.time()
result = self.func(*args, **kwargs)
end = time.time()
print("用时{:.2f}s".format(end - start))
return result
return wrapper# 有改动
@Timer(prefix="curr_time:")# 有改动
def add(a, b):
return a + b
# 等价于:add = Timer(prefix="curr_time:"))(add),将add这个函数转化为了一个Timer对象
result = add(2, 3)# add(Timer对象)使用了它的__call__函数
print(result)
本质是装饰器要装饰的对象,也即装饰器装饰的对象也既可以是函数,也可以是类
def add_str(cls):
def __str__(self):
return str(self.__dict__)
cls.__str__ = __str__
# 把cls的__str__函数替换成自定义的__str__,本质上就是重写了class的__str__函数
return cls
# 因为class本身也是一个object,所以add_str这个函数是一个参数是class,返回值也是class的函数
@add_str
class Myobject:
def __init__(self,a,b):
self.a=a
self.b=b
# 等价于 Myobject=add_str(Myobject)
# 输入一个类,返回一个类,在类里边动动手脚
o=Myobject(1,2)
print(o)#{'a': 1, 'b': 2}
同样道理,类装饰器也可以有带参数的写法
核心:转换成等价形式,你就知道你需要写一个什么东西,它的输入应该是什么,输出应该是什么
objprint, 让你轻松打印python object
支持直接打印对象,原理就是使用了装饰器
另外,评论区有一个可以使得函数无需调用且全局可用的方法,也很神奇,可以看下
functools.partial()一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单
# 将数字转化为二进制
def int2(x, base=2):
return int(x, base)
int2('1000000') # 64
# 可以像下面这样写
int2 = functools.partial(int, base=2)
int2('1000000') # 64
参数:key=len/int/str…
# sort()
l = ['bb','aaaa','c','ddddddddd','fff']
l.sort(key=len)
print(l) # ['c', 'bb', 'fff', 'aaaa', 'ddddddddd']
# sorted()
l = [2,5,1,3,6,4]
print('排序前:',l) # 排序前: [2, 5, 1, 3, 6, 4]
print(sorted(l,key=int)) # [1, 2, 3, 4, 5, 6]
print('排序后:',l) # 排序后: [2, 5, 1, 3, 6, 4]