存档

文章标签 ‘lambda’

lambda 表达式 (in Python)

2016/11/16 7,563

概述lambda

python 中的 lambda 比较简单,只是作为创建匿名函数来使用

  • lambda 只是一个表达式,而不是一个代码块。类似于 C++ 中的 define ,但比 define 要简单.Python 中的 lambda 只能封装有限的逻辑进去。
  • lambda 拥有自己的全名空间,且不能访问自有参数列表之外及全局的参数。

语法

labmda 函数的语法只包含一个语句:

lambda [arg ...] : exception

lambda 可以传入多个参数,使用逗号 “,” 分隔。 exception 使用这些参数进行运算并将结果返回。这里的 exception 隐藏了 return 关键词。 示例:

fun = lambda a,b,c : a+b+c
print "call fun(1,2,3) : " , fun(1,2,3)

以上输出:

call fun(1,2,3) : 6

在 python 中的使用

lambda 的使用比较灵活。例如可以在函数内部定义匿名函数,实现简单逻辑并在函数内部使用。另一个常见的应用场景则是作为匿名函数对象在迭代器中使用。比如:

map(function, iterable, ...)
filter(function, iterable)
reduce(function, iterable[, initializer])
  • map : 对迭代器招待 function 操作,并将操作后的 list 返回
  • filter : function 应该返回一个布尔值,对迭代器操作为 False 的,将从 List 里排除
  • reduce : 对迭代器进行累计操作,即将上一次操作的结果作为function 的第一个参数进行下一次操作。reduce 最后一个参数作为可选参数,将在首先参与运算。

这几个函数的一般用法如下:

def funMap(val):
    val = val + 1
    return val

def funFilter(val):
    return  val % 2 == 0

def funReduce(x,y):
    return x+y

#main==========
#构造数组
lst = map(funMap,range(0,11))
print lst

#过滤出数组中的偶数
lst = filter(funFilter,lst)
print lst

#将数组中的每个数累加(首先加10)
print reduce(funReduce,lst,10)

可以看到,我们需要为每个函数再定义一个函数,作为参数传入。 如果我们使用 lambda, 可以简化这些工作:

#构造数组
lst = map(lambda x : x + 1, range(0,11))
print lst

#过滤出数组中的偶数
lst = filter(lambda x : x % 2 == 0, lst)
print lst

#将数组中的每个数累加(首先加10)
print reduce(lambda x,y : x + y, lst, 10)

上面两种写法都输出:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
[2, 4, 6, 8, 10]
40

但是,显然使用lambda的写法更加优雅。

仿函数(function object,函数对象)

2016/01/12 8,894

引子

前一篇文章讲到了C++11的新特性lambda表达式

lambda表达式的本质是什么呢?为探究这个问题,我们将一段写有lambda表达式的代码反编译,可能会发现一些秘密.

首先写段程序:

//#include...
auto flambda = [](int x,int y)->int{return x + y;};
int main()
{
    cout<<flambda(3,2)<<endl;
    return 0;
}

在调试该代码时我们打开汇编视图,发现如下代码:

callq  0x100000d80 <$_0::operator()(int, int) const>
mov    0x2c4(%rip),%rdi        # 0x100001010
mov    %eax,%esi

其中 <$_0::operator()(int, int) const>      即对应原代码中的lambda表达式。这里一串重载了”()”(operator())操作符的代码,即本文将要了解的仿函数

Note:  此处的 const  ,也应证了前文 mutable 可变范围 中提到的,lambda的调用运算符为”const-by-value”的

  定义

仿函数(finctor)是一种早期的叫法,在C++11中,标准的叫法为函数对象(function object)。仿函数是一种行为类似函数、具有函数特性的对象。

仿函数是一个对象,而不是函数。仿函数的类通过重载函数操作符”()”(operator())来实现函数调用的特性。

通过下面的例子来简单说明如何使用仿函数

#include <functional>
//#include...

class myGreater
{
public:
    bool operator()(int x,int y)  //重载调用操作函数
    {return x>y;}
};

int main()
{
   greater<int> gt;  //lineA
   cout<<boolalpha<<gt(4,3)<<endl;  //lineB
   cout<<greater<int>()(3,4)<<endl; //lineC
   cout<<myGreater()(5,3)<<endl;    //lineD
    return 0;
}
//OUTPUT:
//true
//false
//true

这个例子中,lineA声明了一个对象。这是一个函数对象,其类(结构)定义在functional文件中,是STL内置的模板类。该类用于比较两个参数的大小。

lineB则像函数一样直接给该对象传入两个参数。

lineC是另一种写法。greater<int>() 声明了一个临时对象,然后传入参数(3,4)调用该临时对象。这种写法往往比lineB更加简洁。在STL源码里大量使用了这种写法。

lineD则是使用自定义的函数对象。

Note:lineB中使用了boolalpha,是iostream提供的一个操作符,这将使此后的标准输出中,将bool值输出为”true”或”false”,而不是1/0。于其相反的操作为noboolalpha.

继续阅读

lambda 表达式

2016/01/11 9,346

LAMBDA简介lambda

从C++11开始,c++开始支持lambda表达式。

lambda用来创建一个可以捕获作用域内变量的匿名函数对象的闭包。这通常用来封装传递给算法或异步方法的少量代码块。

例如,简单实现一个Trim函数,去除字符串里的空格:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;

string trimall(string str)
{
    vector<char> vec;
    for_each(str.begin(),str.end(),[&vec](char c){if(!isspace(c)) vec.push_back(c);});
    return string(vec.begin(),vec.end());
}

int main() {
    std::string str = "   Hi, lam b da!";
    
    std::cout << trimall(str);
    
    return 0;
}

//OUTPUT:
//Hi,lambda!

此例中,

[&vec](char c){if(!isspace(c)) vec.push_back(c);}

即是一个lambda表达式。其做为一个匿名函数,被算法  for_each 使用,使得代码更简洁。

继续阅读