【Python学习笔记】变量可以指向函数、函数名本质、函数做另一函数的参数、函数作为返回值、闭包、匿名函数...

#!/usr/bin/env python
#-*- coding:utf-8 -*-
import math# 导入数学公式模块
from collections import Iterable# 判断是否为可迭代对象
import os# 导入os模块


# 函数就是面向过程的程序设计的基本单元,任意一个函数,只要输入是确定的,输出就是确定的

# ★变量可以指向函数
# Python内置的四舍五入函数round()
print round(10.1) # 10.0
print round       # <built-in function round>
# 这说明,round 是函数本身,round(10.1)是函数调用
r = round(10.1) 
print r           # 10.0
r = round
print r           # <built-in function round>
# 函数本身可以赋值给变量,即:变量可以指向函数
print r(10.45)    # 10.0
# 将一个变量指向一个函数后,可以通过变量调用该函数

# ★函数名本质
# 从上面可以看出,完全可以把函数名看成是指向函数的变量
round = 10
# print round(10.1) # 'int' object is not callable
# 这说明round已经不指向四舍五入函数了,同时也说明函数名其实就是指向函数的变量

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

# ★函数做另一函数的参数【类似C语言的函数指针】
# 高阶函数:一个可以接收另外一个函数为它参数的函数
def abs_add(a,b,f):
    return f(a) + f(b)
print u'绝对值相加之和:',abs_add(7,-8,abs)
	
# ★函数作为返回值	
# 高阶函数除了可以接受函数作为参数外,还可以把函数当成返回值返回

# 可变参数求和函数
def sum_var_para(*args):
    sum = 0
    for a in args:
        sum += i
    return sum
# 如果不需要立即求和,而是保存当前状态,然后根据后面需要再计算,怎么办?这时可以先不返回求和结果而是返回求和函数
# 定义一个可以接受可变参数,而且返回求和函数的函数
def temp_sum(*args):
    def sum_var_para():
        sum = 0
        for a in args:
            sum += a
        return sum
    return sum_var_para
print u'调用外部函数:',temp_sum(1,2,3,4,5) # 结果<function sum_var_para at 0x02144D30>
# ★事实证明调用temp_sum()时返回的并不是结果,而是求和函数
# 逻辑上,上面的语句也是不成立的,因为temp_sum()返回的是函数,并不是值
# 调用函数temp_sum(1,2,3,4,5)()时,得到的才是真正的计算求和的结果
f = temp_sum(1,2,3,4,5)
print u'先调用外部再调用内部函数',f() 
# 等效于print temp_sum(1,2,3,4,5)()
# ★分析:函数temp_sum中又定义了函数sum_var_para,并且,内部函数sum_var_para可以引用外部函数temp_sum的参数和局部变量
#       当temp_sum返回函数sum_var_para时,相关参数和变量都保存在返回的函数中,这种结构称为“闭包“
# 每次调用外部函数时,都会返回一个新的函数,即使传入相同的参数	
f1 = temp_sum(1,2,3,4,5)	
f2 = temp_sum(1,2,3,4,5)	
print u'每次调用返回函数是否相同:',f1 == f2
	
# ★闭包	
# 使用闭包应注意:当一个函数返回了一个函数后,其内部的局部变量sum还有可能被新函数引用
# 另一个需要注意的问题是,返回的函数sum_var_para并没有立刻执行,而是直到调用了返回的内部函数sum_var_para时才执行
# ★这个例子,包含了上面两个应该注意的问题
def temp_power():
    result_temp = []
    for i in range(1,4):
        def f():
		    return i * i
        result_temp.append(f)
    return result_temp
print u'调用外部函数:',temp_power()
# 结果是返回了三个求和函数
result1, result2, result3 = temp_power()
print u'先调用外部再调用内部函数:',result1(), result2(), result3()
# 全部都是9而不是想象的1,4,9,原因在于返回的函数f引用了变量i ,但f并非立刻执行。等到3个函数都返回时,它们所引用的变量i 已经变成了3,因此最终结果为9
# ★牢记的一点就是:返回函数不要引用任何循环变量,或者后续会发生变化的变量
# 如果非要引用可变变量,方法是再创建一个函数,将该函数的参数与可变变量当前的值绑定,这样无论该可变变量后续如何更改,已绑定到函数参数的值不变
def count():
    fs = []
    for i in range(1, 4):
        def f(j):
            def g():
                return j*j
            return g
        fs.append(f(i))
    return fs
result1, result2, result3 = count()
print u'先调用外部再调用内部函数:',result1(), result2(), result3()

# ★匿名函数lambda
# def创建的方法是有名称的,lambda函数没有具体的名称,所以叫匿名函数
# 有时候,在传入函数时,并不需要每次那么麻烦的显式定义函数,直接传入到匿名函数会更加方便,而且不必担心函数名冲突

# 无参数的匿名函数
print lambda :x * x    # 结果:<function <lambda> at 0x02362EB0>

# 例:计算一个序列的平方
T = (1,2,3,4,5,6,7,8,9,10)
def power2(x):
    return x * x
L = []                                       # 方法一
for n in T:
    L.append(power2(n))
print u'循环追加:', L
print u'使用map:', map(power2,T)             # 方法二
print u'使用lambda:', map(lambda x: x * x,T) # 方法三
# 匿名函数lambda x: x * x 。关键字lambda 表示匿名函数,冒号前面的x表示函数参数,冒号后是关于参数的表达式
# 实际上就是:def f(x):
#                 return x * x

# 和普通函数一样,匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数
power2 = lambda x: x * x
print power2      # <function <lambda> at 0x0219FDB0>
print power2(2)   # 4

# 同样,也可以把匿名函数作为返回值返回
def build(a, b):
    return lambda: a * a + b * b # lambda不需要自己的参数
print build(3,4)  # <function <lambda> at 0x021A58B0>
print build(3,4)()# 25

# 用lambda表达式求n的阶乘
def fact(n):
    return reduce(lambda x,y: x * y,range(1,n+1))
print fact(5) # 结果:120

# 把自定义函数直接写成lambda的形式
a = lambda x: lambda y: x * y
b = a(2)
print b           # 返回的是内层lambda函数
print b(3)        # 6

# ★小结: 匿名函数有个限制,只能有一个表达式,不用写return,返回值就是该表达式的结果,所以只有一些简单的情况下才可以使用匿名函数
#         对于单行函数,使用lambda可以省去定义函数的过程,让代码更加精简
#         在非多次调用的函数的情况下,lambda表达式即用既得,提高性能。
#         注意:如果for..in..if能做的,最好不要选择lambda
#         lambda只是一个表达式,而def则是一个语句
#         lambda会创建一个函数对象,但不会把这个函数对象赋给一个标识符【即函数名】,而def则会把函数对象赋值给一个变量【即函数名】



运行效果:

161625_7bB4_2913386.png

转载于:https://my.oschina.net/MasterLi161307040026/blog/747745

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值