python:函数的高级特性

很多语言中,都允许把函数本身做为参数,传递给其它参数:即所谓的高阶函数。python中也有类似特性:

一、map/reduce、filter、sorted

hadoop里的map-reduce思想在python里已经变成内置函数了。map是将某个函数逐一作用于列表中的每个元素。reduce则先从列表中取头2个元素,传到指定函数,然后将计算结果与余下元素依次重复,直到List处理完。

1.1 map示例:(将List中的所有元素*10)

def fn_map(x):
    print("fn_map->", x)
    return 10 * x

L = [3, 4, 6, 8]

print(list(map(fn_map, L)))
print("\n")

输出:

fn_map-> 3
fn_map-> 4
fn_map-> 6
fn_map-> 8
[30, 40, 60, 80]

结合map,我们再把reduce函数加上(最终效果:将所有元素*10再平方,最终得出 “平方和”的"平方根")

def fn_sqrt(x, y):
    print("fn_sqrt->", x, ",", y)
    return math.sqrt(x ** 2 + y ** 2)

def fn_map(x):
    print("fn_map->", x)
    return 10 * x

L = [3, 4, 6, 8]

result = reduce(fn_sqrt, map(fn_map, L))
print(result)

print("\n")
print(math.sqrt((3 * 10) ** 2 + (4 * 10) ** 2 + (6 * 10) ** 2 + (8 * 10) ** 2))

注:要先import math,上面的代码输出如下:

fn_map-> 3
fn_map-> 4
fn_sqrt-> 30 , 40
fn_map-> 6
fn_sqrt-> 50.0 , 60
fn_map-> 8
fn_sqrt-> 78.10249675906654 , 80
111.80339887498948

111.80339887498948

上面这个例子,可能实用性不大,下面给个实用性更强的示例,将每个单词的首字母大写,其它字母变小写。

def normalize(name):
    return name[:1].upper() + name[1:].lower()

L1 = [‘adam‘, ‘LISA‘, ‘barT‘]
print(list(map(normalize, L1)))

输出:

[‘Adam‘, ‘Lisa‘, ‘Bart‘]

1.2 filter

filter跟java8里的stream的filter是类似的,可以实现对集合中的元素,按某种规则进行筛选。

示例1:找出10以内的偶数

result = filter(lambda x: x % 2 == 0, range(1, 11))
print(list(result))

# 上面的写法,等效于下面这个
def even(x):
    return x % 2 == 0

print(list(filter(even, range(1, 11))))

输出:

[2, 4, 6, 8, 10]
[2, 4, 6, 8, 10]

示例2:找出200以内的"回数"(即:从左向右,从右向左,都是一样的数,比如:131, 141)

def is_palindrome1(n):
    if n < 10:
        return True
    s = str(n)
    for i in range(0, int(len(s) / 2)):
        if s[i] == s[-i - 1]:
            return True
    return False

def is_palindrome2(n):
    s1 = str(n)
    s2 = list(reversed(s1))
    return list(s1) == s2

print(list(filter(is_palindrome1, range(1, 201))))
print(list(filter(is_palindrome2, range(1, 201))))

输出:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 22, 33, 44, 55, 66, 77, 88, 99, 101, 111, 121, 131, 141, 151, 161, 171, 181, 191]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 22, 33, 44, 55, 66, 77, 88, 99, 101, 111, 121, 131, 141, 151, 161, 171, 181, 191]

  

1.3 sorted

python内置的排序函数sorted,支持数字/字母/以及复杂对象排序,默认是从小到大排序,对于复杂对象的排序规则可以开发者自定义。参考下面的示例:

origin = [-1, 3, -5, 2, -4, 6]
# 从小到大排序
a = sorted(origin)
print(a)

# 按abs绝对值,从小大到排序
a = sorted(origin, key=abs)
print(a)

# 从大到小排序
a = sorted(origin, reverse=True)
print(a)

origin = ["Xy", "Aa", "Bb", "dd", "cC", "aA", "Zo"]

# 按字母ascii值从小到大排序
print(sorted(origin))

# 将字母转大写后的值排序(即:忽略大小写)
print(sorted(origin, key=str.upper))

# 将字母转大写后的值倒排序
print(sorted(origin, key=str.upper, reverse=True))

# 复杂对象排序
origin = [(‘Bob‘, 75), (‘Adam‘, 92), (‘Bart‘, 66), (‘Lisa‘, 88)]

def by_name(t):
    return t[0]

# 按人名排序
print(sorted(origin, key=by_name))

def by_score(t):
    return t[1]

# 按得分倒排
print(sorted(origin, key=by_score, reverse=True))

输出:

[-5, -4, -1, 2, 3, 6]
[-1, 2, 3, -4, -5, 6]
[6, 3, 2, -1, -4, -5]
[‘Aa‘, ‘Bb‘, ‘Xy‘, ‘Zo‘, ‘aA‘, ‘cC‘, ‘dd‘]
[‘Aa‘, ‘aA‘, ‘Bb‘, ‘cC‘, ‘dd‘, ‘Xy‘, ‘Zo‘]
[‘Zo‘, ‘Xy‘, ‘dd‘, ‘cC‘, ‘Bb‘, ‘Aa‘, ‘aA‘]
[(‘Adam‘, 92), (‘Bart‘, 66), (‘Bob‘, 75), (‘Lisa‘, 88)]
[(‘Adam‘, 92), (‘Lisa‘, 88), (‘Bob‘, 75), (‘Bart‘, 66)]

二、延迟计算/闭包

python的函数定义可以嵌套(即:函数内部再定义函数),利用这个特性很容易实现延迟计算:

import time

def export1(month):
    print("export1 month:", month, " doing...")
    time.sleep(5)
    print("export1 done!")

def export2(month):
    def do():
        print("export2 month:", month, " doing...")
        time.sleep(5)
        print("export2 done!")

    return do

export1(10)

print("----------------")

r2 = export2(10)
print(r2)
r2()

这里我们模拟一个耗时的导出功能(假设:要求传入月份,然后导出该月的报表数据),export1为常规版本,调用export1就会马上执行。而export2则是返回一个内部函数do(),调用export2后,返回的是一个Function,并没有实际执行(可以理解为: 返回的是业务处理算法,而非处理结果),真正需要结果的时候,再来调用"返回函数"。

上面的代码输出如下:

export1 month: 10  doing...
export1 done!
----------------
<function export2.<locals>.do at 0x107a24a60>
export2 month: 10  doing...
export2 done!

  

闭包

很多语言都支持闭包特性,python中当然少不了这个,参考下面的示例:

def my_sqrt1(n):
    r = []

    def do():
        for i in range(1, n + 1):
            r.append(i ** 2)
        return r

    return do

a = my_sqrt1(4)
print(type(a))
b = a()
print(type(b))
print(b)

输出:

<class ‘function‘>
<class ‘list‘>
[1, 4, 9, 16]  

闭包有一个经典的坑:不要在闭包函数中使用“值会发生变化的变量"(比如:for循环中的变量)。原因是:python中的闭包本质上是是"内部函数"延时计算,如果有循环变量,循环过程中闭包函数并不会执行,等循环结束了,闭包中引用的循环变量其实是循环结束后最终的值。说起来有点绕口,看下面的示例:

def my_sqrt2(n):
    r = []
    for i in range(1, n + 1):
        def do():
            r.append(i ** 2)
            return r

    return do

a = my_sqrt2(4)
print(type(a))
b = a()
print(type(b))
print(b)

输出:

<class ‘function‘>
<class ‘list‘>
[16]

解释一下:调用a = my_sqrt2(4)时,my_sqrt2(4)马上执行完了,这时候里面的fox循环执行完了,最后i的值停在4,然后这个值被封闭在do函数里,并没有马上执行。然后再调用a()时,这时候才真正调用do()函数,此时i值=4,所以最终r[]列表里,就只追回了一个值4*4=16 

如果非要使用循环变量,只能想招儿把这个循环变量,也封闭到一个内部函数里,然后再使用,比如下面这样:

def my_sqrt3(n):
    def f(j):
        def g():
            return j ** 2

        return g

    r = []
    for i in range(1, n + 1):
        r.append(f(i))

    return r

a = my_sqrt3(4)
print(type(a))

for x in a:
    print(x())

这个例子仔细研究下蛮有意思的,r.append(f(i)),列表里追加的并非计算结果,而是f(j)里返回的函数g,所以a = my_sqrt3(4)这里,a得到的是一个function组成的list,然后list里的每个g函数实例,都封闭了当次循环的变量i,因为闭包的缘故,i值已经被封印在g内部,不管外部的for循环如何变量,都不会影响函数g。

输出如下:

<class ‘list‘>
1
4
9
16

最后再来看一个廖老师教程上的闭包作业题,用闭包的写法写一个计数器:

def create_counter1():
    r = [0]

    def counter():
        r[0] += 1
        return r[0]

    return counter

count = create_counter1();

print([count(), count(), count()])

输出:

[1, 2, 3] 

对于有洁癖的程序员,可能会觉得要额外设置一个只保存1个元素的list,有点浪费。可以换种写法:

def create_counter2():
    n = 0

    def counter():
        nonlocal n
        n += 1
        return n

    return counter

count = create_counter2();

print([count(), count(), count()])

输出:

[1, 2, 3]  

注意这里有一个关键字nonlocal,号称是python3新引入的关键字,为的是让闭包的内部函数里面,能读写内部函数外的变量。(但是在第1种写法中,r=[0]不也是定义在外部么?区别就是list是复杂的变量类型,而第2种写法中n是简单类型的变量,做为python初学者,不是很理解这个哲学思想^_~)

参考文档:

1、廖雪峰的python教程:函数式编程

原文地址:https://www.cnblogs.com/yjmyzz/p/8918925.html

时间: 2024-10-12 19:28:18

python:函数的高级特性的相关文章

Python的一些高级特性

内容基本上来自于廖雪峰老师的blog相当于自己手打了一遍,加强加强理解吧. http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000 Python的一些高级特性 Slot python是动态语言,所谓动态,就是可以先创建类的实例,之后再动态绑定属性或方法,比如下边这个例子: class Student(object) pass s=Student() s.name="asd" 注

Python面向对象编程高级特性

***这里还是根据网上资料,主要是廖雪峰老师的教程学习的笔记,主要介绍python面向对象的高级特性,笔记不全,只是记录自己觉得容易出错的地方*** 1.python作为一种动态语言,他的动态绑定机制允许在运行过程中动态的给class或者对象实例添加方法和属性,这个在静态语言中比如java是很难做到的: 1)动态绑定属性: 2)动态绑定方法 给一个实例绑定的方法对于其他实例和类都是不可见的:(这里也说明给一个实例动态绑定方法必须用MethodType(func, instance)) 但是给类绑

函数,高级特性

4.调用函数 (1)Python 内置了很多有用的函数,我们可以直接调用: abs()  ##########求绝对值 cmp()   #########比较大小fact()   #############递归函数实现 cmp截图: 练习:############实现递归函数##################################################### n! = 1x2x3x4x.......(n-1)xn= (n-1)!xn = (n-2)!x(n-1)xn1!  

python自测——高级特性

高级特性 70.函数装饰器有什么作用?请列举说明?71.Python 垃圾回收机制?72.魔法函数 __call__怎么使用?73.如何判断一个对象是函数还是方法?[email protected] 和@staticmethod 用法和区别75.Python 中的接口如何实现?76.Python 中的反射了解么?77.metaclass 作用?以及应用场景?78.hasattr() getattr() setattr()的用法79.请列举你知道的 Python 的魔法方法及用途.80.如何知道一

002-python函数、高级特性

1.函数 1.1 定义函数 在Python中,定义一个函数要使用def语句,依次写出函数名.括号.括号中的参数和冒号:,然后,在缩进块中编写函数体,函数的返回值用return语句返回 自定义一个求绝对值的my_abs函数为例: def my_abs(x): if x >= 0: return x else: return -x 1.2 函数调用 如果已经把my_abs()的函数定义保存为abstest.py文件了,那么,可以在该文件的当前目录下启动Python解释器,用from abstest

python基础-对象高级特性

一.实例绑定: 二.使用__slots__: 三.@property:python内置装饰器 decorator 四.多重继承:Mixin 五.定制类: 1. __str__ 和 __repr__: 打印一个实例 2. __iter__: 被用于 for ... in循环 3.__getitem__ :现得像list那样按照下标取出元素,需要实现__getitem__()方法 4.__getattr__ : 动态返回一个属性 5.__call__ : 对实例本身进行调用 六.使用元类:metac

Python快速学习-高级特性

1.切片 取一个list或tuple的部分元素是非常常见的操作 L = ['hello','the','world','and','my','love'] 取前三个元素 L[0:3],L[:3] 取倒数第一个元素:L[-1](倒数第一个元素的索引-1) 取后两个元素:L[-2:] 创建0-99的数列:L=list(range(100)) 取前十个元素:L[:10] 取后十个元素:L[-10:] 前11-20个元素:L[10:20] 前10个数,每两个取一个:L[:10:2] 所有数,每5个取一个

python学习之高级特性

一.生成式1.定义 生成式就是一个用来快速生成特定语法形式的表达式.列表生成式:用来快速生成列表字典生成式:用来快速生成字典集合生成式:用来快速生成集合2.语法格式 (1)普通的语法格式:[exp for iter_var in iterable](2)带过滤功能语法格式: [exp for iter_var in iterable if_exp](3)循环嵌套语法格式: [exp for iter_var_A in iterable_A for iter_var_B in iterable_B

python的一些高级特性(列表生成式)

列表生成式 如果要生成[1x1, 2x2, 3x3, ..., 10x10]怎么做? >>> [x * x for x in range(1, 11)] [1, 4, 9, 16, 25, 36, 49, 64, 81, 100] for循环后面还可以加上if判断,这样我们就可以筛选出仅偶数的平方: >>> [x * x for x in range(1, 11) if x % 2 == 0] [4, 16, 36, 64, 100] 还可以使用两层循环,可以生成全排列