04 - Python入门 - 函数

张开发
2026/4/9 5:28:07 15 分钟阅读

分享文章

04 - Python入门 - 函数
上一篇我们学了 Python 的基础语法所有代码都是从上往下顺序执行的。但真实的程序不可能把所有逻辑都写成流水线我们需要把代码拆分成一个个函数每个函数负责一件事需要的时候调用就行。这篇除了函数本身还会讲 Python 中非常实用的lambda表达式、列表推导式、字典推导式等语法糖。这些东西第一次见可能觉得有点花哨但用熟了你就会发现它们能大幅简化代码刷算法题的时候尤其好用。01.函数定义与调用函数就是一段可以重复调用的代码块给它一个名字需要的时候调用就行。Python 用def关键字定义函数# 定义一个函数计算两个数的和# def 是关键字add 是函数名a 和 b 是参数defadd(a,b):returnab# 没有返回值的函数不需要写 return或者写 return Nonedefgreet(name):print(你好name)# 调用函数resultadd(3,5)# 输出8print(result)# 输出你好Pythongreet(Python)# 函数的返回值可以直接参与运算# 输出19print(add(10,9))注意 Python不需要声明参数类型和返回值类型——因为 Python 是动态类型语言变量的类型在运行时自动确定。你传什么进去它就是什么类型。还有一点Python 是用缩进来划分代码块的。def下面缩进的部分就是函数体缩进结束函数就结束了。一般用 4 个空格缩进。02.参数默认参数定义函数时可以给参数设置默认值调用时如果不传这个参数就用默认值# b 有默认值 2调用时可以不传defpower(a,b2):returna**b# 只传一个参数b 使用默认值 2# 输出9即 3 的 2 次方print(power(3))# 传两个参数b 3# 输出27即 3 的 3 次方print(power(3,3))# 也可以用参数名指定这叫关键字参数# 输出16即 2 的 4 次方print(power(a2,b4))默认参数有个规则有默认值的参数必须放在没有默认值的参数后面。你想想就知道了如果放前面Python 就分不清你传的值是给谁的。可变参数 *args 和 **kwargs有时候你不确定函数会接收多少个参数Python 提供了两种方式来处理语法说明*args接收任意多个位置参数打包成一个元组类似列表但不可修改下一篇会讲**kwargs接收任意多个关键字参数打包成一个字典# *args 把多余的位置参数打包成元组defmy_sum(*args):print(收到的参数,args)total0fornuminargs:totalnumreturntotal# 可以传任意多个参数# 输出收到的参数 (1, 2, 3)# 输出6print(my_sum(1,2,3))# 输出收到的参数 (10, 20, 30, 40)# 输出100print(my_sum(10,20,30,40))# **kwargs 把多余的关键字参数打包成字典defprint_info(**kwargs):print(收到的参数,kwargs)forkey,valueinkwargs.items():print(f{key}{value})# 用关键字参数调用# 输出# 收到的参数 {name: Alice, age: 25, city: 北京}# name Alice# age 25# city 北京print_info(nameAlice,age25,city北京)*args和**kwargs只是约定俗成的名字你也可以叫*numbers或**options关键是前面的*和**。说实话你自己写代码的时候用到*args和**kwargs的场景不会太多。但看别人的代码时经常会遇到所以要认识它们。多返回值Python 的函数可以返回多个值本质上是返回一个元组然后用拆包的方式接收# 返回商和余数defdivide(a,b):returna//b,a%b# 用两个变量接收两个返回值元组拆包q,rdivide(10,3)# 输出商 3, 余数 1print(f商 {q}, 余数 {r})# 其实返回的是一个元组resultdivide(10,3)# 输出(3, 1)print(result)# 如果只需要其中一个值用 _ 占位_,remainderdivide(17,5)# 输出余数 2print(f余数 {remainder})_是一个约定俗成的我不需要这个值的写法Python 不会报错但实际上_也是一个合法变量名只是我们用它来表示这个值我不关心。多返回值在刷算法题时很实用比如一个函数既要返回最大值又要返回最大值的下标用多返回值就很方便。03.lambda 表达式lambda是一种创建匿名函数的简洁写法适合写那些只用一次的简单函数。语法lambda 参数: 表达式# 普通函数写法defadd(a,b):returnab# 等价的 lambda 写法add2lambdaa,b:ab# 两者效果一样# 输出8print(add(3,5))# 输出8print(add2(3,5))# lambda 只能写一个表达式不能写多行语句# 常用于简单的运算squarelambdax:x**2# 输出25print(square(5))你可能会想这跟普通函数有啥区别单独用确实没什么区别。lambda真正的用武之地是作为参数传递给其他函数最经典的就是排序# 一组学生每个人是 (姓名, 成绩) 的元组students[(Alice,88),(Bob,95),(Charlie,72),(Diana,91)]# 按成绩从高到低排序# key 参数告诉 sorted 用什么规则排序# lambda x: x[1] 表示取每个元组的第二个元素成绩rankedsorted(students,keylambdax:x[1],reverseTrue)# 输出[(Bob, 95), (Diana, 91), (Alice, 88), (Charlie, 72)]print(ranked)# 按姓名长度排序by_name_lensorted(students,keylambdax:len(x[0]))# 输出[(Bob, 95), (Alice, 88), (Diana, 91), (Charlie, 72)]print(by_name_len)# 对普通列表也行按绝对值排序nums[-3,1,-4,1,5,-9,2,-6]sorted_numssorted(nums,keylambdax:abs(x))# 输出[1, 1, 2, -3, -4, 5, -6, -9]print(sorted_nums)sorted函数的key参数接收一个函数这个函数告诉sorted“用什么规则来比较元素”。用lambda写一行就搞定非常简洁。如果不用lambda你就得单独定义一个函数然后传进去多写好几行。刷算法题时sorted lambda的组合用得非常频繁一定要熟练掌握。04.列表推导式列表推导式List Comprehension是 Python 中非常有特色的语法能用一行代码生成一个列表。看完你就知道为什么大家都说 Python 代码简洁了。# 传统写法生成 0~9 每个数的平方squares[]forxinrange(10):squares.append(x**2)# 输出[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]print(squares)# 列表推导式写法一行搞定squares2[x**2forxinrange(10)]# 输出[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]print(squares2)# 再看几个例子# 每个元素乘以 2doubled[x*2forxinrange(5)]# 输出[0, 2, 4, 6, 8]print(doubled)# 生成字符串列表names[alice,bob,charlie]upper_names[name.upper()fornameinnames]# 输出[ALICE, BOB, CHARLIE]print(upper_names)语法模板[表达式 for 变量 in 可迭代对象]意思是遍历可迭代对象对每个元素执行表达式把结果收集成一个新列表。本质上就是for循环 append的简写。带条件过滤列表推导式还可以加上if条件只保留满足条件的元素# 只保留偶数evens[xforxinrange(10)ifx%20]# 输出[0, 2, 4, 6, 8]print(evens)# 只保留正数nums[-3,1,-4,1,5,-9,2,-6]positives[xforxinnumsifx0]# 输出[1, 1, 5, 2]print(positives)# 过滤 变换可以同时做# 只取偶数然后算平方even_squares[x**2forxinrange(10)ifx%20]# 输出[0, 4, 16, 36, 64]print(even_squares)# 从字符串列表中筛选长度大于 3 的并转为大写words[hi,hello,hey,world,ok]long_words[w.upper()forwinwordsiflen(w)3]# 输出[HELLO, WORLD]print(long_words)语法模板[表达式 for 变量 in 可迭代对象 if 条件]先过滤if再变换表达式最后收集成列表。一行代码干了三件事很爽吧嵌套推导式列表推导式可以嵌套最常见的用途是创建二维列表# 创建 3 行 4 列的二维列表初始值都是 0# 外层循环 3 次行内层循环 4 次列matrix[[0forjinrange(4)]foriinrange(3)]# 输出[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]print(matrix)# 修改某个元素验证一下matrix[1][2]99# 输出[[0, 0, 0, 0], [0, 0, 99, 0], [0, 0, 0, 0]]print(matrix)# 创建乘法表前 5 行table[[i*jforjinrange(1,6)]foriinrange(1,6)]forrowintable:print(row)# 输出# [1, 2, 3, 4, 5]# [2, 4, 6, 8, 10]# [3, 6, 9, 12, 15]# [4, 8, 12, 16, 20]# [5, 10, 15, 20, 25]⚠️这里要特别注意一个坑创建二维列表不能用[[0]*4]*3这种写法。因为 *3 复制的是引用三行指向的是同一个列表对象修改一行其他行也会变。用列表推导式 [[0 for j in range(4)] for i in range(3)] 才是正确的做法每行都是独立的列表。这个坑在刷算法题时非常容易踩一定要记住。05.字典推导式 / 集合推导式既然列表有推导式字典和集合自然也有。语法几乎一样只是把[]换成{}。# 字典推导式{key: value for 变量 in 可迭代对象}# 生成 1~5 的平方字典squares_dict{x:x**2forxinrange(1,6)}# 输出{1: 1, 2: 4, 3: 9, 4: 16, 5: 25}print(squares_dict)# 从两个列表生成字典keys[name,age,city]values[Alice,25,北京]info{k:vfork,vinzip(keys,values)}# 输出{name: Alice, age: 25, city: 北京}print(info)# 字典推导式也可以带条件过滤# 只保留值大于 3 的filtered{k:vfork,vinsquares_dict.items()ifv3}# 输出{2: 4, 3: 9, 4: 16, 5: 25}print(filtered)# 集合推导式{表达式 for 变量 in 可迭代对象}# 注意集合会自动去重nums[1,2,2,3,3,3,4,4,4,4]unique_squares{x**2forxinnums}# 输出{16, 1, 4, 9}集合无序print(unique_squares)字典推导式用{k:v for ...}有冒号集合推导式用{x for ...}没冒号。区别就在这。另外代码中用到的zip函数很实用它能把两个列表拉链式配对后面刷题经常用到。

更多文章