装饰器还没搞懂,搞懂了再来继续写吧~ 函数既可作为返回值也可作为函数的参数…一切都是对象,一切都是指针,一切都是东西… 返回函数(引用)和返回函数值是不一样滴…. ◡̈⃝︎⋆︎*
函数式编程
**函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函数,还允许返回一个函数!**
一. 高阶函数
变量可以指向函数 ;
函数名也是变量 ;
函数可以作为return的返回值 ;
函数可以作为另一个函数的参数 。
1.1 变量指向函数
   在讲变量和字符串的时候我们讲过,变量就是一个对象,可以当作一个指针使用,而函数名也是一个变量,也就是一个对象。函数名其实就是指向函数的变量!注意,函数名是一个变量!变量!变量!当作指针用。
   既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数 。
见过两种函数赋值给变量的形式 ,这两种形式是有区别的,分别总结一下。 一种是
a = f
另一种是
a = f()
1. a = f
型属于将变量指向函数。
如下用示例说明:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 print (abs (-10 ))print (abs )输出: 10 <built-in function abs > ------------------------------------------------------------------------------------------ 可见,abs (-10 )是函数调用,而abs 是函数本身。 要获得函数调用结果,我们可以把结果赋值给变量: x = abs (-10 ) print (x)输出: 10 ------------------------------------------------------------------------------------------ 但是,如果把函数本身赋值给变量呢? f = abs print (f)输出: <built-in function abs > ------------------------------------------------------------------------------------------ 结论:函数本身也可以赋值给变量,即:变量可以指向函数。 如果一个变量指向了一个函数,那么,可否通过该变量来调用这个函数?用代码验证一下: f = abs print (f(-10 ))输出: 10 ------------------------------------------------------------------------------------------ 成功!说明变量f现在已经指向了abs 函数本身。直接调用abs ()函数和调用变量f()完全相同。
说明变量f现在已经指向了abs函数本身。直接调用abs()
函数和调用变量f()
完全相同。这是廖雪峰老师python教程上的例子,现在调用f()
和调用abs()
是一样的了。
再举一个工厂函数的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 def maker (N ): def action (X ): return X**N return action ------------------------------------------------------------------------------------------ 这个嵌套函数的外层返回值为内层函数的函数名,注意没有括号,这里有无括号是有很大区别的。此时调用外部函数: f=maker(2 ) //此时进入maker(2 ),且定义了一个action(X)函数,然后返回action函数名(对象)给f ------------------------------------------------------------------------------------------ 那么如上所述,f便指向了action函数,且限制条件为N=2 ,可以理解为f为N等于2 时的action函数。我们来调用它: print (f(3 )) //此时相当于调用了cation(3 )函数,这也是在外部使用内部嵌套函数的方法, //因为内部嵌套函数是不允许在外部访问的。 输出: 9 //证明f和action函数是一样的。------------------------------------------------------------------------------------------ 如上的示例也可以用print (f=maker(2 )(3 ))来输出结果一样,两个括号连在一起相当于执行了这两个函数。 def maker (N ): def a (c ): return c**N return a f=maker(2 )(3 ) print (f)OUTPUT: 9
2. a = f()
型属于将f()的返回值赋值给a的过程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 这里的a仅仅接收f()的返回值,如果f()没有返回值,那么a即被赋值为None 。这里值得注意的一点是, 在a=f()的执行过程中,f()会运行一次,如: def add (x,y ): z = x+y print (z) a = add(3 ,4 ) print ('******我是分隔符,嘿嘿嘿******' )print (a)OUTPUT: 7 ******我是分隔符,嘿嘿嘿****** None ------------------------------------------------------------------------------------------ 这里在分隔符前输出了7 ,说明赋值过程函数add执行了,然而a的值为None ,且只能通过print 语句才可以显示。 这是因为add()函数没有return 语句。
1.2 传入函数与返回函数名
一、传入函数(把函数作为参数)
  既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数 。
一个最简单的高阶函数:
1 2 def add(x, y, f): return f(x) + f(y)
当我们调用add(-5, 6, abs)
时,参数x,y和f分别接收-5,6和abs,根据函数定义,我们可以推导计算过程为:
1 2 3 4 5 x = -5 y = 6 f = abs f(x) + f(y) ==> abs(-5) + abs(6) ==> 11 return 11
用代码验证一下:
1 2 3 4 5 6 def add (x, y, f ): return f(x) + f(y) print (add(-5 , 6 , abs ))OUTPUT: 11
总结: 编写高阶函数,就是让函数的参数能够接收别的函数。把函数作为参数传入,这样的函数称为高阶函数,函数式编程就是指这种高度抽象的编程范式 。
二、返回函数名(把函数名作为返回值)
  高阶函数除了可以接受函数作为参数外,还可以把函数名作为结果值返回。注意Python3返回的是迭代器对象 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 '''我们来实现一个可变参数的求和。通常情况下,求和的函数是这样定义的:''' 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 ) print (f)OUTPUT: <function lazy_sum.<locals >.sum at 0x101c6ed90 > '''调用函数f时,才真正计算求和的结果:''' f() OUTPUT: 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==f2 OUTPUT: False 'f1()和f2()的调用结果互不影响。'
三、闭包
  注意到返回的函数在其定义内部引用了局部变量args
,所以,当一个函数返回了一个函数后,其内部的局部变量还被新函数引用,所以,闭包用起来简单,实现起来可不容易。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 '''另一个需要注意的问题是,返回的函数并没有立刻执行,而是直到调用了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)) return fs '再看看结果:' >>> f1, f2, f3 = count()>>> f1()1 >>> f2()4 >>> f3()9 '''缺点是代码较长,可利用lambda函数缩短代码。'''
二. 装饰器