技術圖文:Python 匿名函數 VS. C# Lambda表達式

背景

前段時間在知識星球上立了一個Flag,至少寫10篇關於 Python,Matlab 和 C# 對比的總結。

這是第 2 篇,從定義和應用兩個角度來對比 Python 的匿名函數 與 C# 的Lambda表達式。


匿名函數/Lambda表達式的定義

Python 匿名函數

在 Python 裏有兩類函數:

  • 第一類:用 def 關鍵詞定義的正規函數
  • 第二類:用 lambda 關鍵詞定義的匿名函數

python 使用 lambda 關鍵詞來創建匿名函數,而非def關鍵詞,它沒有函數名,其語法結構如下:

lambda argument_list: expression
  • lambda - 定義匿名函數的關鍵詞。
  • argument_list - 函數參數,它們可以是位置參數、默認參數、關鍵字參數,和正規函數裏的參數類型一樣。
  • :- 冒號,在函數參數和表達式中間要加個冒號。
  • expression - 只是一個表達式,輸入函數參數,輸出一些值。

注意:

  • expression 中沒有 return 語句,因爲 lambda 不需要它來返回,表達式本身結果就是返回值。
  • 匿名函數擁有自己的命名空間,且不能訪問自己參數列表之外或全局命名空間裏的參數。

【例】

def sqr(x):
    return x ** 2


print(sqr)
# <function sqr at 0x000000BABD3A4400>

y = [sqr(x) for x in range(10)]
print(y)
# [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

lbd_sqr = lambda x: x ** 2
print(lbd_sqr)
# <function <lambda> at 0x000000BABB6AC1E0>

y = [lbd_sqr(x) for x in range(10)]
print(y)
# [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]


sumary = lambda arg1, arg2: arg1 + arg2
print(sumary(10, 20))  # 30

func = lambda *args: sum(args)
print(func(1, 2, 3, 4, 5))  # 15

C# Lambda表達式

Lambda 表達式是 匿名委託 更爲簡潔的一種寫法,這個概念來自函數式編程,很多語言都加入了這個功能。通俗點講,你需要寫一個函數,但是懶得給它起名字,而且懶得寫那麼多封裝和類,並且可能就這個地方調用,其它地方幾乎不調用這段代碼,那麼我們就可以用這個來搞定。

Lambda 運算符:

“=>” 運算符將表達式分爲兩部分,左邊指定輸入參數,右邊是 Lambda 的主體,表達式或語句塊。

Lambda 表達式:

  • 一個參數:param => expr;
  • 多個參數:(param-list) => expr;

【例】

static void Print<T>(List<T> lst)
{
    foreach (T item in lst)
    {
        Console.Write(item + " ");
    }
    Console.WriteLine(Environment.NewLine);
}

static void Main(string[] args)
{
    Func<int, int> sqr = delegate (int x) { return x * x; };
    Func<int, int> lbd_sqr = x => x * x;

    List<int> y1 = new List<int>();
    List<int> y2 = new List<int>();
    for (int i = 0; i < 10; i++)
    {
        y1.Add(sqr(i));
        y2.Add(lbd_sqr(i));
    }
    Print(y1);// 0 1 4 9 16 25 36 49 64 81
    Print(y2);// 0 1 4 9 16 25 36 49 64 81

    Func<int, int, int> sumary = (arg1, arg2) => arg1 + arg2;
    Console.WriteLine(sumary(10, 20)); //30

    Func<int[], int> sum = x => x.Sum();
    Console.WriteLine(sum(new int[] { 1, 2, 3, 4, 5 }));//15
}

匿名函數/Lambda表達式的應用

Python 匿名函數

匿名函數 常常應用於函數式編程的高階函數 (high-order function)中。

如,在 filtermap函數中的應用:

  • filter(function, iterable) 過濾序列,過濾掉不符合條件的元素,返回一個迭代器對象,如果要轉換爲列表,可以使用 list() 來轉換。

【例】

odd = lambda x: x % 2 == 1
templist = filter(odd, [1, 2, 3, 4, 5, 6, 7, 8, 9])
print(list(templist))  # [1, 3, 5, 7, 9]
  • map(function, *iterables) 根據提供的函數對指定序列做映射。

【例】

m1 = map(lambda x: x ** 2, [1, 2, 3, 4, 5])
print(list(m1))  
# [1, 4, 9, 16, 25]

m2 = map(lambda x, y: x + y, [1, 3, 5, 7, 9], [2, 4, 6, 8, 10])
print(list(m2))  
# [3, 7, 11, 15, 19]

除了 Python 這些內置函數,我們也可以自己定義高階函數。

【例】

def apply_to_list(fun, some_list):
    return fun(some_list)

lst = [1, 2, 3, 4, 5]
print(apply_to_list(sum, lst))
# 15

print(apply_to_list(len, lst))
# 5

print(apply_to_list(lambda x: sum(x) / len(x), lst))
# 3.0

C# Lambda表達式

Lambda 表達式常常應用於 LINQ 的擴展函數中。

  • Where 擴展:屬於System.Linq,基於謂詞篩選值序列,返回一個包含輸入序列中滿足條件的元素集合。
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate);

【例】

static void Print<T>(T[] nums)
{
    foreach (T item in nums)
    {
        Console.Write(item + " ");
    }
    Console.WriteLine(Environment.NewLine);
}

static void Main(string[] args)
{
    int[] nums = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    int[] result = nums.Where(x => x % 2 == 1).ToArray();
    Print(result);// 1 3 5 7 9
}
  • Select 擴展:屬於System.Linq,將序列中的每個元素投影到新表單。
public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector);

【例】

static void Print<T>(T[] nums)
{
    foreach (T item in nums)
    {
        Console.Write(item + " ");
    }
    Console.WriteLine(Environment.NewLine);
}

static void Main(string[] args)
{
    int[] nums = new int[] { 1, 2, 3, 4, 5 };
    int[] result = nums.Select(x => x * x).ToArray();
    Print(result);//1 4 9 16 25  

    int[][] nums1 = new int[5][] {
        new int[]{ 1,2 },
        new int[]{ 3,4 },
        new int[]{ 5,6 },
        new int[]{ 7,8 },
        new int[]{ 9,10 }
    };
    result = nums1.Select(x => x[0] + x[1]).ToArray();
    Print(result);// 3 7 11 15 19
}

【例】

static int Apply_To_List(Func<int[],int> func,int[] list)
{
    return func(list);
}
static double Apply_To_List(Func<int[], double> func, int[] list)
{
    return func(list);
}

static void Main(string[] args)
{
    int[] nums = new int[] { 1, 2, 3, 4, 5 };
    int result = Apply_To_List(x => x.Sum(), nums);
    Console.WriteLine(result); // 15

    result = Apply_To_List(x => x.Length, nums);
    Console.WriteLine(result); // 5

    double result1 = Apply_To_List(x => 1.0 * x.Sum() / x.Length, nums);
    Console.WriteLine(result1); // 3
}

總結

函數式編程是當今比較流行的以簡潔著稱的一種編程方式。而 匿名函數/Lambda表達式 是這種編程方式的基礎。

前段時間看到教務處通知老師們上報線上考試的方案,感覺這個學期可能不會開學了。今天看到通知6月8日畢業生可以申請返校,也就意味着讓他們回去收拾東西辦理離校手續準備畢業了。不管怎樣,希望疫情儘快過去吧。

今天就到這裏吧。See You!


當前活動


我是 終身學習者“老馬”,一個長期踐行“結伴式學習”理念的 中年大叔

我崇尚分享,渴望成長,於2010年創立了“LSGO軟件技術團隊”,並加入了國內著名的開源組織“Datawhale”,也是“Dre@mtech”、“智能機器人研究中心”和“大數據與哲學社會科學實驗室”的一員。

願我們一起學習,一起進步,相互陪伴,共同成長。

後臺回覆「搜搜搜」,隨機獲取電子資源!
歡迎關注,請掃描二維碼:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章