python高阶函数看不懂_Python进阶:高阶函数的详细说明

这篇文章讲述了Python进阶:高阶函数的详细说明有需要的朋友可以参考

函数式编程

函数是Python内建支持的一种封装,我们通过把大段代码拆成函数,通过一层一层的函数调用,就可以把复杂任务分解成简单的任务,这种分解可以称之为面向过程的程序设计。函数就是面向过程的程序设计的基本单元。

而函数式编程(请注意多了一个“式”字)——Functional Programming,虽然也可以归结到面向过程的程序设计,但其思想更接近数学计算。

我们首先要搞明白计算机(Computer)和计算(Compute)的概念。

在计算机的层次上,CPU执行的是加减乘除的指令代码,以及各种条件判断和跳转指令,所以,汇编语言是最贴近计算机的语言。

而计算则指数学意义上的计算,越是抽象的计算,离计算机硬件越远。

对应到编程语言,就是越低级的语言,越贴近计算机,抽象程度低,执行效率高,比如C语言;越高级的语言,越贴近计算,抽象程度高,执行效率低,比如Lisp语言。

函数式编程就是一种抽象程度很高的编程范式,纯粹的函数式编程语言编写的函数没有变量,因此,任意一个函数,只要输入是确定的,输出就是确定的,这种纯函数我们称之为没有副作用。而允许使用变量的程序设计语言,由于函数内部的变量状态不确定,同样的输入,可能得到不同的输出,因此,这种函数是有副作用的。

函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函数,还允许返回一个函数!

Python对函数式编程提供部分支持。由于Python允许使用变量,因此,Python不是纯函数式编程语言。

高阶函数

高阶函数英文叫Higher-order function。什么是高阶函数?我们以实际代码为例子,一步一步深入概念。

变量可以指向函数

以Python内置的求绝对值的函数abs()为例,调用该函数用以下代码:

>>> abs(-10)10

但是,如果只写abs呢?

>>> abs

可见,abs(-10)是函数调用,而abs是函数本身。

要获得函数调用结果,我们可以把结果赋值给变量:

>>> x = abs(-10)>>> x10

但是,如果把函数本身赋值给变量呢?

>>> f = abs

>>> f

结论:函数本身也可以赋值给变量,即:变量可以指向函数。

如果一个变量指向了一个函数,那么,可否通过该变量来调用这个函数?用代码验证一下:

>>> f = abs>>> f(-10)10

成功!说明变量f现在已经指向了abs函数本身。直接调用abs()函数和调用变量f()完全相同。

函数名也是变量

那么函数名是什么呢?函数名其实就是指向函数的变量!对于abs()这个函数,完全可以把函数名abs看成变量,它指向一个可以计算绝对值的函数!

如果把abs指向其他对象,会有什么情况发生?

>>> abs = 10

>>> abs(-10)

Traceback (most recent call last):

File "", line 1, in

TypeError: 'int' object is not callable

把abs指向10后,就无法通过abs(-10)调用该函数了!因为abs这个变量已经不指向求绝对值函数而是指向一个整数10!

当然实际代码绝对不能这么写,这里是为了说明函数名也是变量。要恢复abs函数,请重启Python交互环境。

注:由于abs函数实际上是定义在import builtins模块中的,所以要让修改abs变量的指向在其它模块也生效,要用import builtins; builtins.abs = 10。

传入函数

既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。

一个最简单的高阶函数:

def add(x, y, f): return f(x) + f(y)

当我们调用add(-5, 6, abs)时,参数x,y和f分别接收-5,6和abs,根据函数定义,我们可以推导计算过程为:

x = -5

y = 6

f = abs

f(x) + f(y) ==> abs(-5) + abs(6) ==> 11return 11

用代码验证一下:

>>> add(-5, 6, abs)11

编写高阶函数,就是让函数的参数能够接收别的函数。

小结

把函数作为参数传入,这样的函数称为高阶函数,函数式编程就是指这种高度抽象的编程范式。

map/reduce

Python内建了map()和reduce()函数。

如果你读过Google的那篇大名鼎鼎的论文“MapReduce: Simplified Data Processing on Large Clusters”,你就能大概明白map/reduce的概念。

我们先看map。map()函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。

举例说明,比如我们有一个函数f(x)=x2,要把这个函数作用在一个list [1, 2, 3, 4, 5, 6, 7, 8, 9]上,就可以用map()实现如下:

现在,我们用Python代码实现:

>>> def f(x):... return x * x

...>>> r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])>>> list(r)

[1, 4, 9, 16, 25, 36, 49, 64, 81]

map()传入的第一个参数是f,即函数对象本身。由于结果r是一个Iterator,Iterator是惰性序列,因此通过list()函数让它把整个序列都计算出来并返回一个list。

你可能会想,不需要map()函数,写一个循环,也可以计算出结果:

L = []for n in [1, 2, 3, 4, 5, 6, 7, 8, 9]:

L.append(f(n))

print(L)

的确可以,但是,从上面的循环代码,能一眼看明白“把f(x)作用在list的每一个元素并把结果生成一个新的list”吗?

所以,map()作为高阶函数,事实上它把运算规则抽象了,因此,我们不但可以计算简单的f(x)=x2,还可以计算任意复杂的函数,比如,把这个list所有数字转为字符串:

>>> list(map(str, [1, 2, 3, 4, 5, 6, 7, 8, 9]))['1', '2', '3', '4', '5', '6', '7', '8', '9']

只需要一行代码。

再看reduce的用法。reduce把一个函数作用在一个序列[x1, x2, x3, ...]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算,其效果就是:

reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)

比方说对一个序列求和,就可以用reduce实现:

>>> from functools import reduce>>> def add(x, y):... return x + y

...>>> reduce(add, [1, 3, 5, 7, 9])25

当然求和运算可以直接用Python内建函数sum(),没必要动用reduce。

但是如果要把序列[1, 3, 5, 7, 9]变换成整数13579,reduce就可以派上用场:

>>> from functools import reduce>>> def fn(x, y):... return x * 10 + y

...>>> reduce(fn, [1, 3, 5, 7, 9])13579

这个例子本身没多大用处,但是,如果考虑到字符串str也是一个序列,对上面的例子稍加改动,配合map(),我们就可以写出把str转换为int的函数:

>>> from functools import reduce>>> def fn(x, y):... return x * 10 + y

...>>> def char2num(s):... return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[s]

...>>> reduce(fn, map(char2num, '13579'))13579

整理成一个str2int的函数就是:

from functools import reducedef str2int(s): def fn(x, y): return x * 10 + y def char2num(s): return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[s] return reduce(fn, map(char2num, s))

还可以用lambda函数进一步简化成:

from functools import reducedef char2num(s): return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[s]def str2int(s): return reduce(lambda x, y: x * 10 + y, map(char2num, s))

也就是说,假设Python没有提供int()函数,你完全可以自己写一个把字符串转化为整数的函数,而且只需要几行代码!

lambda函数的用法在后面介绍。

filter

Python内建的filter()函数用于过滤序列。

和map()类似,filter()也接收一个函数和一个序列。和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。

例如,在一个list中,删掉偶数,只保留奇数,可以这么写:

def is_odd(n): return n % 2 == 1

list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))# 结果: [1, 5, 9, 15]

把一个序列中的空字符串删掉,可以这么写:

def not_empty(s): return s and s.strip()

list(filter(not_empty, ['A', '', 'B', None, 'C', ' ']))# 结果: ['A', 'B', 'C']

可见用filter()这个高阶函数,关键在于正确实现一个“筛选”函数。

注意到filter()函数返回的是一个Iterator,也就是一个惰性序列,所以要强迫filter()完成计算结果,需要用list()函数获得所有结果并返回list。

sorted

排序算法

排序也是在程序中经常用到的算法。无论使用冒泡排序还是快速排序,排序的核心是比较两个元素的大小。如果是数字,我们可以直接比较,但如果是字符串或者两个dict呢?直接比较数学上的大小是没有意义的,因此,比较的过程必须通过函数抽象出来。

Python内置的sorted()函数就可以对list进行排序:

>>> sorted([36, 5, -12, 9, -21])[-21, -12, 5, 9, 36]

此外,sorted()函数也是一个高阶函数,它还可以接收一个key函数来实现自定义的排序,例如按绝对值大小排序:

>>> sorted([36, 5, -12, 9, -21], key=abs)

[5, 9, -12, -21, 36]

key指定的函数将作用于list的每一个元素上,并根据key函数返回的结果进行排序。对比原始的list和经过key=abs处理过的list:

list = [36, 5, -12, 9, -21]keys = [36, 5, 12, 9, 21]

然后sorted()函数按照keys进行排序,并按照对应关系返回list相应的元素:

keys排序结果 => [5, 9, 12, 21, 36]

| | | | |

最终结果 => [5, 9, -12, -21, 36]

我们再看一个字符串排序的例子:

>>> sorted(['bob', 'about', 'Zoo', 'Credit'])['Credit', 'Zoo', 'about', 'bob']

默认情况下,对字符串排序,是按照ASCII的大小比较的,由于'Z' < 'a',结果,大写字母Z会排在小写字母a的前面。

现在,我们提出排序应该忽略大小写,按照字母序排序。要实现这个算法,不必对现有代码大加改动,只要我们能用一个key函数把字符串映射为忽略大小写排序即可。忽略大小写来比较两个字符串,实际上就是先把字符串都变成大写(或者都变成小写),再比较。

这样,我们给sorted传入key函数,即可实现忽略大小写的排序:

>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower)

['about', 'bob', 'Credit', 'Zoo']

要进行反向排序,不必改动key函数,可以传入第三个参数reverse=True:

>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True)

['Zoo', 'Credit', 'bob', 'about']

从上述例子可以看出,高阶函数的抽象能力是非常强大的,而且,核心代码可以保持得非常简洁。

小结

sorted()也是一个高阶函数。用sorted()排序的关键在于实现一个映射函数。

返回函数

函数作为返回值

高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回。

我们来实现一个可变参数的求和。通常情况下,求和的函数是这样定义的:

def calc_sum(*args):

ax = 0 for n in args:

ax = ax + n return ax

但是,如果不需要立刻求和,而是在后面的代码中,根据需要再计算怎么办?可以不返回求和的结果,而是返回求和的函数:

def lazy_sum(*args): def sum():

ax = 0 for n in args:

ax = ax + n return ax return sum

当我们调用lazy_sum()时,返回的并不是求和结果,而是求和函数:

>>> f = lazy_sum(1, 3, 5, 7, 9)

>>> f

.sum at 0x101c6ed90>

调用函数f时,才真正计算求和的结果:

>>> f()25

在这个例子中,我们在函数lazy_sum中又定义了函数sum,并且,内部函数sum可以引用外部函数lazy_sum的参数和局部变量,当lazy_sum返回函数sum时,相关参数和变量都保存在返回的函数中,这种称为“闭包(Closure)”的程序结构拥有极大的威力。

请再注意一点,当我们调用lazy_sum()时,每次调用都会返回一个新的函数,即使传入相同的参数:

>>> f1 = lazy_sum(1, 3, 5, 7, 9)>>> f2 = lazy_sum(1, 3, 5, 7, 9)>>> f1==f2False

f1()和f2()的调用结果互不影响。

闭包

注意到返回的函数在其定义内部引用了局部变量args,所以,当一个函数返回了一个函数后,其内部的局部变量还被新函数引用,所以,闭包用起来简单,实现起来可不容易。

另一个需要注意的问题是,返回的函数并没有立刻执行,而是直到调用了f()才执行。我们来看一个例子:

def count():

fs = [] for i in range(1, 4): def f(): return i*i

fs.append(f) return fs

f1, f2, f3 = count()

在上面的例子中,每次循环,都创建了一个新的函数,然后,把创建的3个函数都返回了。

你可能认为调用f1(),f2()和f3()结果应该是1,4,9,但实际结果是:

>>> f1()9>>> f2()9>>> f3()9

全部都是9!原因就在于返回的函数引用了变量i,但它并非立刻执行。等到3个函数都返回时,它们所引用的变量i已经变成了3,因此最终结果为9。

返回闭包时牢记的一点就是:返回函数不要引用任何循环变量,或者后续会发生变化的变量。

如果一定要引用循环变量怎么办?方法是再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变:

def count(): def f(j): def g(): return j*j return g

fs = [] for i in range(1, 4):

fs.append(f(i)) # f(i)立刻被执行,因此i的当前值被传入f() return fs

再看看结果:

>>> f1, f2, f3 = count()>>> f1()1>>> f2()4>>> f3()9

缺点是代码较长,可利用lambda函数缩短代码。

小结

一个函数可以返回一个计算结果,也可以返回一个函数。

返回一个函数时,牢记该函数并未执行,返回函数中不要引用任何可能会变化的变量。

匿名函数

当我们在传入函数时,有些时候,不需要显式地定义函数,直接传入匿名函数更方便。

在Python中,对匿名函数提供了有限支持。还是以map()函数为例,计算f(x)=x2时,除了定义一个f(x)的函数外,还可以直接传入匿名函数:

>>> list(map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9]))[1, 4, 9, 16, 25, 36, 49, 64, 81]

通过对比可以看出,匿名函数lambda x: x * x实际上就是:

def f(x): return x * x

关键字lambda表示匿名函数,冒号前面的x表示函数参数。

匿名函数有个限制,就是只能有一个表达式,不用写return,返回值就是该表达式的结果。

用匿名函数有个好处,因为函数没有名字,不必担心函数名冲突。此外,匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数:

>>> f = lambda x: x * x

>>> f

at 0x101c6ef28>

>>> f(5)

25

同样,也可以把匿名函数作为返回值返回,比如:

def build(x, y): return lambda: x * x + y * y

小结

Python对匿名函数的支持有限,只有一些简单的情况下可以使用匿名函数。

偏函数

Python的functools模块提供了很多有用的功能,其中一个就是偏函数(Partial function)。要注意,这里的偏函数和数学意义上的偏函数不一样。

在介绍函数参数的时候,我们讲到,通过设定参数的默认值,可以降低函数调用的难度。而偏函数也可以做到这一点。举例如下:

int()函数可以把字符串转换为整数,当仅传入字符串时,int()函数默认按十进制转换:

>>> int('12345')12345

但int()函数还提供额外的base参数,默认值为10。如果传入base参数,就可以做N进制的转换:

>>> int('12345', base=8)5349

>>> int('12345', 16)74565

假设要转换大量的二进制字符串,每次都传入int(x, base=2)非常麻烦,于是,我们想到,可以定义一个int2()的函数,默认把base=2传进去:

def int2(x, base=2): return int(x, base)

这样,我们转换二进制就非常方便了:

>>> int2('1000000')64>>> int2('1010101')85

functools.partial就是帮助我们创建一个偏函数的,不需要我们自己定义int2(),可以直接使用下面的代码创建一个新的函数int2:

>>> import functools>>> int2 = functools.partial(int, base=2)>>> int2('1000000')64>>> int2('1010101')85

所以,简单总结functools.partial的作用就是,把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单。

注意到上面的新的int2函数,仅仅是把base参数重新设定默认值为2,但也可以在函数调用时传入其他值:

>>> int2('1000000', base=10)1000000

最后,创建偏函数时,实际上可以接收函数对象、*args和**kw这3个参数,当传入:

int2 = functools.partial(int, base=2)

实际上固定了int()函数的关键字参数base,也就是:

int2('10010')

相当于:

kw = { 'base': 2 }int('10010', **kw)

当传入:

max2 = functools.partial(max, 10)

实际上会把10作为*args的一部分自动加到左边,也就是:

max2(5, 6, 7)

相当于:

args = (10, 5, 6, 7)

max(*args)

结果为10。

小结

当函数的参数个数太多,需要简化时,使用functools.partial可以创建一个新的函数,这个新函数可以固定住原函数的部分参数,从而在调用时更简单。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/559393.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java callable接口_Java多线程之Callable接口的实现有返回值的线程

import java.util.concurrent.Callable;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;//在主线程获取callable线程返回值时&#xff0c;如果callable线程还存在线程没有执行完&#xff0c;则主线程…

python聊天软件实现_python实现点对点聊天程序

用Python实现点对点的聊天&#xff0c;2个程序&#xff0c;一个是client.py&#xff0c;一个是server.py&#xff0c;通过本机地址127.0.0.1连接进行通信&#xff0c;利用多线程把发送消息和接收消息分开独立进行。client代码&#xff1a;import socketimport sysimport thread…

java编译器代码检查_Java编译器可以优化此代码吗?

我拥有的Java 8编译器似乎并没有对其进行优化.编译后使用“ javap -c”检查字节码&#xff1a;public static void main(java.lang.String[]);Code:0: new #2 // class java/util/Random3: dup4: invokespecial #3 // Method java/util/Random."":()V7: invokevirtua…

python中rgb_python - 图像的RGB矩阵

Taking an image as input, how can I get the rgb matrix corresponding to it?I checked out the numpy.asarray function. Does that give me the rgb matrix or some other matrix?解决方案The simplest answer is to use the NumPy and SciPy wrappers around PIL. Ther…

java volatile lock_Java并发学习笔记 -- Java中的Lock、volatile、同步关键字

Java并发一、锁1. 偏向锁1. 思想背景来源&#xff1a;HotSpot的作者经过研究发现&#xff0c;大多数情况下&#xff0c;锁不仅不存在多线程竞争&#xff0c;而且总是由同 一线程多次获得&#xff0c;为了让线程获得锁的代价更低而引入了偏向锁。原理&#xff1a;在对象头和栈帧…

python 数组赋值_pythonamp;numpy的赋值

有点编程基础的童鞋看到这个标题可能会有点懵逼&#xff0c;这还是个问题吗&#xff1f;不就是个等号()解决问题嘛&#xff01;我也希望是如此简单&#xff0c;因为上个星期被这个问题折磨到崩溃&#xff01;一般的python程序需要赋值时的确是通过等号()实现的&#xff0c;不管…

java字符串匹配dp_[OI]字符串DP小结

顾名又思义&#xff0c;是在字符串上进行的DP操作。因为字符串本身可以看作是一个序列&#xff0c;所以有些时候字符串DP可以用区间DP来解决。P2246 SAC#1 - Hello World(升级版)题目描述在讲义的某一面&#xff0c;他看见了一篇文章。这篇文章由英文字母(大小写均有)、数字、和…

python打包成exe导入文件_【转载】将python脚本打包成exe文件

标签&#xff1a;exe文件也就是可以直接执行的文件。通常我们编好的带py后缀的脚本文件都是需要在有python的环境下执行&#xff0c;每次通过Win R打开运行窗口再输入powershell打开控制台,再千辛万苦地cd c:\python27 (change directory)转换目录到py文件的目录下。最终还是要…

java线上问题定位_java定位线上问题

3、jstack: Java 提供的命令。可以查看某个进程的当前线程栈运行情况。根据 这个命令的输出可以定位某个进程的所有线程的当前运行状态、运行代码,以及 是否死锁等等......A、//int a,b,c B、/** int a,b ,c */ C、{int a,b,c} */ D、/* int a,b String a */ 30、Java 目前支持…

python排名上升_TIOBE:2019年7月全球编程语言排行 Python热度继续上升

与上个月相比&#xff0c;Python 的指数又增加了不少&#xff0c;由 8.530% 上升到 9.260%。我们还留意到&#xff0c;TIOBE 对这期榜单的标题描述是“Perl is one of the victims of Python’s hype”&#xff0c;大意是说Perl 成为了过度炒作 Python 的受害者之一。TIOBE 认为…

java界面化二叉排序树_105-线索化二叉树代码实现2

2.网上数据结构和算法的课程不少&#xff0c;但存在两个问题&#xff1a;1)授课方式单一&#xff0c;大多是照着代码念一遍&#xff0c;数据结构和算法本身就比较难理解&#xff0c;对基础好的学员来说&#xff0c;还好一点&#xff0c;对基础不好的学生来说&#xff0c;基本上…

python截图识别文字代码_10几行代码,用python打造实时截图识别OCR

你一定用过那种“OCR神器”&#xff0c;可以把图片中的文字提取出来&#xff0c;极大的提高工作效率。今天&#xff0c;我们就来做一款实时截图识别的小工具。顾名思义&#xff0c;运行程序时&#xff0c;可以实时的把你截出来的图片中的文字识别出来。、&#xff01;下次&…

我的世界java 内存_我的世界如何分配内存

如果你在运行Minecraft时出现内存错误等问题&#xff0c;你可能需要给Minecraft分配更多内存来解决运行故障。如果你玩的是新版本的Minecraft&#xff0c;那么你可以从启动器里直接分配内存(RAM)。如果你使用的是旧版本&#xff0c;那么你需要创建一些文件来改变Minecraft内存使…

python数据拟合固定参数_如何将数据拟合到非理想二极管方程(隐式非线性函数)并检索参数 - python...

散乱数据图我需要将(x&#xff0c;y)-数据拟合到具有两个变量(x和y)的方程式中&#xff0c;并检索5个未知参数。我正在编写一个脚本&#xff0c;以处理来自简单.txt文件的IV数据(电流电压)&#xff0c;并将其拟合为称为非理想二极管方程的方程&#xff1b;这是一个隐式非线性函…

java学生签到系统视频教程_手把手教你做一个Java web学生信息、选课、签到考勤、成绩管理系统附带完整源码及视频开发教程...

四个阶段的Java web学生信息系统视频教程终于录制完成了&#xff0c;系统用到的知识点有&#xff1a;jspservletmysqljqueryajax&#xff0c;前端采用的是当下最流行的easyui管理框架&#xff0c;全部采用面向接口的MVC三层设计模式&#xff0c;是大家学习Java web实战项目不可…

python做网络的仿真_用python自动化仿真HFSS,超简易

python是一款适用性极强的编程语言。一直期待HFSS(三维全波电磁场仿真的行业标准)能有python接口。后知后觉的本人才发现原来HFSS16(2015版本)已经不止支持VB脚本&#xff0c;还增加了python支持&#xff0c;当然它用的是Ironpython&#xff0c;基于.NET&#xff0c;和Cpython还…

为什么网格布局不显示java_java – 在GridLayout中不显示组件的FlowLayout?

我正在创建一个应用程序,作为某种类型的中心,用户可以将快捷方式存储到他们喜欢的应用程序并轻松启动它们.不过,我在使用FlowLayout时遇到了一些问题.当我使用GridLayout时,组件显示完美.当我使用FlowLayout时,根本没有任何显示.网格布局&#xff1a;FlowLayout中&#xff1a;我…

python爬取qq音乐歌词风变编程_爬取QQ音乐歌词

#!/usr/bin/env python3# -*- coding: utf-8 -*-# DESC&#xff1a; 爬取歌手前3页歌曲的歌词都爬取下来&#xff0c;并按歌名分别保存# Date: 2020-05-21import requestsimport re,osos.makedirs(music,exist_okTrue)## 添加请求头headers {user-agent:Mozilla/5.0 (Windows …

php post请求后端拿不到值_Ajax 提交POST后,后台php 无法获取$POST值

当 contentType 为 application/x-www-form-urlencoded 时(默认值)才能用 $_POST 得到传入的数据。但是使用 application/json;charsetutf-8不是 php 所能识别的类型声明&#xff0c;不能替你解析。所以只能用 php://input 取得&#xff0c;并用 parse_str 自行解析而形如 a1&a…

springbean的生命周期_spring bean生命周期(涵盖spring常用接口的载入)

spring bean生命周期流程图&#xff1a;​​​​其中包含了很多常用的接口&#xff0c;可以参考spring 常用接口&#xff1b;下面写个例子证明下&#xff1a;1.实现InitializingBean以及各个Aware接口public class UserB implements InitializingBean , BeanFactoryAware , Bea…