更多连载请查看【python】
Don’t say so much!
文章目录
1 闭包
如果在一个函数的内部定义了另一个函数,外部的我们叫他外函数,内部的我们叫他内函数。
在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用。这样就构成了一个闭包。
def a(x):
def b(y):
print (x*y)
return b
i = a(5)
print (i)
print (type(i))
a(5)(6)
结果为
<function a.<locals>.b at 0x7f7e6429a9d8>
<class 'function'>
30
闭包(Closure)是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数。
这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。
所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。
闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。
简单来说,闭包就是根据不同的配置信息得到不同的结果~
来自:Python进阶系列连载(8)——闭包(上)
看个例子就懂
def func(str1):
print("你的电脑基本配置是:")
def func_in(str2):
print(str1 + str2)
return func_in
a = func("16G内存")
a("2T硬盘(小明要求的)")
print("-"*30)
b = func("1080Ti显卡")
b("2T硬盘(小刚要求的)")
print("-"*30)
a("2T硬盘+粉红色外观(小红要求的)")
output
你的电脑基本配置是:
16G内存2T硬盘(小明要求的)
------------------------------
你的电脑基本配置是:
1080Ti显卡2T硬盘(小刚要求的)
------------------------------
16G内存2T硬盘+粉红色外观(小红要求的)
常见错误
def a(x):
x = 5
def b(y):
x = x*x+y
return x
return b
a(5)(6)
结果为
UnboundLocalError: local variable 'x' referenced before assignment
修改 python2,放在容器中
def a(x):
x = [5]
def b(y):
x[0] = x[0]**2+6
return x[0]
return b
a(5)(6)
结果为31
修改 python3,nonlocal 关键字
nonlocal关键字用来在函数或其他作用域中使用外层(非全局)变量。
def a(x):
x = 5
def b(y):
nonlocal x
x = x*x+y
return x
return b
a(3)(6)
a(4)(6)
a(5)(6)
结果都为31
注意下面两种情况的区别
def funOut():
def funIn():
print('宾果!你成功访问到我啦!')
return funIn() ##返回的是函数的调用
funOut()#调用
结果为
宾果!你成功访问到我啦!
def funOut():
def funIn():
print('宾果!你成功访问到我啦!')
return funI n## 返回的是函数名
funOut()()#调用
结果为
宾果!你成功访问到我啦!
def funX():
x = 5
def funY():
nonlocal x
x += 1
return x
return funY
a = funX()
print(a())
print(a())
print(a())
结果为
6
7
8
分析一波,只要 a 没有被重新赋值,funx()就没有被释放,局部变量 x 就不会被初始化!
2 高阶函数 map()
高阶函数:一个函数可以作为参数传给另外一个函数,或者一个函数的返回值为另外一个函数(若返回值为该函数本身,则为递归),满足其一则为高阶函数。
def add_func(x,y):
return x+y
def mul_func(a,b,c,d,add_func):
return add_func(a,b)*add_func(c,d)
print(mul_func(1,2,3,4,add_func))
output
21
上面例子中, add_func
就是一般的函数,mul_func
中的形参含有函数,属于高阶函数
下面我们来介绍高阶函数 map
——映射
map() 会根据提供的函数对指定序列做映射。
Help on class map in module builtins:
class map(object)
| map(func, *iterables) --> map object
|
| Make an iterator that computes the function using arguments from
| each of the iterables. Stops when the shortest iterable is exhausted.
|
| Methods defined here:
|
| __getattribute__(self, name, /)
| Return getattr(self, name).
|
| __iter__(self, /)
| Implement iter(self).
|
| __new__(*args, **kwargs) from builtins.type
| Create and return a new object. See help(type) for accurate signature.
|
| __next__(self, /)
| Implement next(self).
|
| __reduce__(...)
| Return state information for pickling.
第一个参数 function 以参数序列中的每一个元素调用 function 函数,返回包含每次 function 函数返回值的新列表。
简单一点可以理解为,map
是把函数和参数绑定在一起。
就像群体攻击技能(锁定技)一样,map(群体技能,【对象1,对象2,…,对象n】)
参考 Python进阶系列连载(9)——Python内置高阶函数map(上)
先来个简单的例子,以前面定义的加法函数为例
def add(x,y):
return x+y
print(map(add,[1],[2])) # 把函数和要输入的参数 map 起来
print(type(map(add,[1],[2])))
list1 = list(map(add,[1],[2])) #转化为列表
print(list1)
output
<map object at 0x0000019D86DC1080>
<class 'map'>
[3]
支持多输入
def add(x,y):
return x+y
list2 = list(map(add,[1,2],[2,3]))
print(list2)
output
[3, 5]
用 tuple 的形式来传入函数的参数也可以
def add(x,y):
return x+y
list3 = list(map(add,(1,2),(2,3)))
print(list3)
output
[3, 5]
下面看一下稍微复杂一点的例子,
求解列表中每个元素的平方
实现求解列表中每个元素的平方,生成新的列表
import time
list1 = [x for x in range(1000000)] # 新建列表,元素 0~999999
# 方式一:创立列表逐个元素添加求解
start = time.time()
list2 = []
for i in list1:
list2.append(i**2)
print(time.time()-start)
# 方式二:列表生成式
start = time.time()
list3 = [x**2 for x in list1]
print(time.time()-start)
# 方式三:map
start = time.time()
list4 = list(map(lambda x: x**2, list1))
print(time.time()-start)
output
0.48311352729797363
0.33878660202026367
0.4389934539794922
可以看出列表生成式速度还是很给力的
验证码不区分大小写
password = ["xikYLSD57qdASDF4sdf", "adfSADoi123povETRGa", "adEFASDFlkxm78wSDF3r"]
list1 = list(map(lambda x: x.upper(), password))
print(list1)
output
['XIKYLSD57QDASDF4SDF', 'ADFSADOI123POVETRGA', 'ADEFASDFLKXM78WSDF3R']
去掉列表中字符串的空格
1)方式一,借助字符串的 strip()
函数,可以去掉首尾给定的字符,默认为空格和换行符
list1 = ["I", "Love ", " KobeBryant"]
print(list1)
list2 = list(map(lambda x: x.strip(), list1))
print(list2)
output
['I', 'Love ', ' KobeBryant']
['I', 'Love', 'KobeBryant']
OK 不错,功能实现了,不过下面情况呢?
list1 = ["I", "Lo ve ", " Kobe Bryant"]
print(list1)
list2 = list(map(lambda x: x.strip(), list1))
print(list2)
output
['I', 'Lo ve ', ' Kobe Bryant']
['I', 'Lo ve', 'Kobe Bryant']
strip()
面对字符串中间出现的空格符略显无力,
此时我们可以采用 replace()
方法,把空格 “ ” 替换成 “”,参考 【python】基本数据类型(1)
list3 = list(map(lambda x: x.replace(" ", ""), list1))
print(list3)
output
['I', 'Love', 'KobeBryant']
利用map 进行列表的类型转换
list1 = list(map(int, ['1', '2', '3']))
list2 = list(map(float, [1, 2, 3]))
print(list1, list2)
output
[1, 2, 3] [1.0, 2.0, 3.0]
3 高阶函数 reduce()
参考 Python进阶系列连载(12)——Python内置高阶函数reduce(下)
reduce 也有缩小的意思,只不过,这里的缩小指的不是物理上的,而是对一个这个reduce高阶函数传入的参数(序列 或者说是 可迭代对象)进行"缩小"操作!
python 3 中,reduce 被放在了 functools
库中了,不能像 map
那样直接调用
def add(a,b):
result = a + b
print(f"{a} + {b} = {result}")
return result
from functools import reduce
result = reduce(add, list(range(1,10)))
print("结果:",result,"\n")
result = reduce(add, list(range(1,10)), 100) # 有初始值
print("结果:",result)
output
1 + 2 = 3
3 + 3 = 6
6 + 4 = 10
10 + 5 = 15
15 + 6 = 21
21 + 7 = 28
28 + 8 = 36
36 + 9 = 45
结果: 45
100 + 1 = 101
101 + 2 = 103
103 + 3 = 106
106 + 4 = 110
110 + 5 = 115
115 + 6 = 121
121 + 7 = 128
128 + 8 = 136
136 + 9 = 145
结果: 145
计算过程如下
这样看起来也没有什么特别之处啊,我 sum
也可以求和耶~
如果是乘法呢? reduce
的作用就发挥出来了,看看下面的例子
from functools import reduce
def mul(a,b):
result = a * b
print(f"{a} * {b} = {result}")
return result
print(reduce(mul,[1,2,3,4]))
output
1 * 2 = 2
2 * 3 = 6
6 * 4 = 24
24
from functools import reduce
list1 = [x for x in range(5)] # 0~4
def add_func(x,y):
return 10*x+y
print(reduce(add_func, list1)) # 无初始化的值
print((((10*0 + 1)*10 + 2)*10 + 3)*10 + 4) # 详细的计算过程
print(reduce(add_func, list1, 1)) # 有初始化的值
print(((((10*1 + 0)*10 + 1)*10 + 2)*10 + 3)*10 + 4) # 详细的计算过程
output
1234
1234
101234
101234
相当于把每个位置上的数组合在一起形成了一个数,哈哈,妙蛙种子吃着妙脆角进了米奇妙妙屋,妙到家了~
嫌蛮烦的话用下面一句话就可以 print(reduce(lambda x, y: 10*x+y, list1, 1))
Ps:
阶乘可以直接调用 math
库
import math
print(math.factorial(5))
output
120
补充
b=map(lambda x:x*x,[1,2,3])
c = [i for i in b]
print(c)
d = [i for i in b]
print(d)
output
[1, 4, 9]
[]
原因是 map() 函数返回的是一个迭代器,并用对返回结果使用了 yield,这样做的目的在于节省内存。
如果不用 yield,那么在列表中的元素非常大时,将会全部装入内存,这是非常浪费内存的,同时也会降低效率
4 高阶函数 filter()
参考
filter() 函数用于过滤序列,过滤掉不符合条件的元素,返回一个迭代器对象,如果要转换为列表,可以使用 list() 来转换。
该接收两个参数,第一个为函数,第二个为序列,序列的每个元素作为参数传递给函数进行判定,然后返回 True 或 False,最后将返回 True 的元素放到新列 filter(function, iterable)
Help on class filter in module builtins:
class filter(object)
| filter(function or None, iterable) --> filter object
|
| Return an iterator yielding those items of iterable for which function(item)
| is true. If function is None, return the items that are true.
|
| Methods defined here:
|
| __getattribute__(self, name, /)
| Return getattr(self, name).
|
| __iter__(self, /)
| Implement iter(self).
|
| __new__(*args, **kwargs) from builtins.type
| Create and return a new object. See help(type) for accurate signature.
|
| __next__(self, /)
| Implement next(self).
|
| __reduce__(...)
| Return state information for pickling.
def func1(a):
return a%2
tmp = range(10)
print (filter(func1,tmp))
list(filter(func1,tmp))
结果为
<filter object at 0x7f7e642580b8>
[1, 3, 5, 7, 9]
注意是把迭代的输入到函数中,输出函数为 true 时的输入值
用上面的匿名函数简化下代码如下
tmp = range(10)
list(filter(lambda x:x%2,tmp))
第一个参数为函数名,可以为空
list(filter (None,[1,2,0,False,True]))
结果为
[1, 2, True]
下面看看一些简单的例子
list1 = [x for x in range(20)] # 0~19
print(list(filter(lambda x: x >= 10, list1))) # 筛选出大于等于 10 的数字
print(list(filter(lambda x: x % 2 == 1, list1))) # 筛选出所有奇数
output
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
下面展示下更复杂的应用,比如找素数
import numpy as np
list1 = [x for x in range(1, 501)]
def isprime(n):
if n < 2:
return False
for i in range(2, int(np.sqrt(n))+1):
if n % i == 0:
return False
return True
list2 = list(filter(isprime, list1))
print(list2)
output
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499]
更简洁的写法
list3 = list(filter(lambda x: all(x % y != 0 for y in range(2, x)), range(2, 13)))
print(list3)
output
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499]
优化下,缩减判断空间
list3 = list(filter(lambda x: all(x % y != 0 for y in range(2, int(x**0.5)+1)), range(2, 501)))
print(list3)
output
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499]
filter 去掉假
alist = [1,0,"","a",[],(),{},False]
b = list(filter(bool, alist))
print(b)
output
[1, 'a']
5 partial()
func = functools.partial(func, *args, **keywords)
func
: 需要被扩展的函数,返回的函数其实是一个类 func 的函数*args
: 需要被固定的位置参数**kwargs
: 需要被固定的关键字参数# 如果在原来的函数 func 中关键字不存在,将会扩展,如果存在,则会覆盖
下面来个简单的例子
from functools import partial
def add(*args, **kwargs):
# 打印位置参数
for n in args:
print(n)
print("-"*20)
# 打印关键字参数
for k, v in kwargs.items():
print('%s:%s' % (k, v))
# 暂不做返回,只看下参数效果,理解 partial 用法
add(1, 2, 3, v1=10, v2=20)
output
1
2
3
--------------------
v1:10
v2:20
看看 partial
add_partial = partial(add, 10, k3=30, k2=20)
add_partial(1, 2, 3, k1=10)
output
10
1
2
3
--------------------
k3:30
k2:20
k1:10
覆盖
add_partial = partial(add, 10, k3=30, k2=20)
add_partial(1, 2, 3, k3=10)
# *arg 的魔法
def func(*arg):
num = 0
for x in arg:
num = num + x
print(num) # 600
func(100, 200, 300)
output
600
附录
all()
print(all([])) # True
print(all(())) # True
print(all(["", "1","2"])) # False
print(all(["0", "1","2"])) # True
Note:
- 更多连载请查看【python】