一次编写,终身受益:Python 函数的“减法”艺术
写到这里的时候,我对 Python 的感觉又变了一次。
前面那些内容,已经让我慢慢知道了怎么输入、怎么判断、怎么循环、怎么整理信息、怎么处理报错。
可真正开始写稍微长一点的代码时,我又碰到了另一个很烦的问题。
很多内容在重复。
同样的动作写一遍。
换个地方,再写一遍。
同样的逻辑改一次,后面还要跟着改很多次。
那种感觉很像你明明已经知道该怎么做了,可还是要一遍遍从头来。
也就是从函数开始,我第一次明显感觉到,代码终于不只是“能跑”,它开始学着把已经想清楚的动作收起来,留着以后继续用。
1. 函数最先让我松一口气的,是很多重复动作终于不用再重写了
最开始接触函数时,我对它最朴素的理解就是:把一段会反复用到的代码包起来。
defpower(x, n=2):return x ** nprint(power(4, 3))print(power(6))
这段代码很简单,但它已经把函数最重要的味道带出来了。
你不用每次都重新写“求幂”这件事。
只要把规则定义好,后面想用的时候直接叫它就行。
也就是从这里开始,我第一次不再把代码看成一行一行分散摆着的句子。
它开始像一个个已经整理好的动作块。
2. 参数这件事,让我第一次看懂“同一个动作,也可以因人而异”
函数最妙的一点,不只是能复用,还在于它不是僵死的。
definfos(name, age=21, gender='女'):return'大家好,我叫%s,我今年%d岁,我是一名%s生' % (name, age, gender)print(infos('栀栀', 22, '女'))print(infos('jack'))print(infos('lily', gender='男'))
写到这里的时候,我会很明显地感觉到,函数不是把一个动作冻住。
它更像是把“动作的骨架”先写好,然后把变化的部分留给参数去决定。
这对我来说特别重要。
因为我第一次看见,原来复用不是死板重复,而是同一种处理方式可以面对不同情况。
所以这一段最值得记住的知识点其实很清楚:
3. return 让我明白,函数不是做完就算了,它还要把结果带回来
刚学函数时,我一开始很容易把“打印出来”和“返回回来”混在一起。
后来我才慢慢发现,这两件事不是一回事。
defsum_2(a, b):return a + bresult = sum_2(9, 8)print(result)
print() 更像是把东西展示给你看。
return 则是在告诉函数:把这个结果交回去,后面还可以继续用。
这一点一旦想通,我对函数的理解就会稳很多。
因为函数不再只是“做一件事”,它还能把结果交给别的代码接着往下走。
也就是从这里开始,我第一次觉得,代码内部开始有了真正的协作感。
4. *args 和 **kwargs 让我第一次意识到,函数也可以很有弹性
再往后学到可变参数时,我会明显感觉到,函数又松开了一点。
deftotal(*args): result = 0for i in args: result += i * ireturn resultprint(total(1, 4, 5, 6))defshow_info(**kwargs):for k, v in kwargs.items():print(k, v)show_info(name='栀栀', age=22)
这时候函数不再要求你每次都用一模一样的输入方式。
它可以接一串值,也可以接一组键值对。
所以我后来会把这一段记成:
- •
**kwargs 常用来接收不定数量的键值参数
这一点很像现实里的很多沟通。
有时候你只需要几个固定信息。
有时候对方给你的内容并不完全一样,那你就得留出更灵活的入口。
5. 作用域让我第一次真正感觉到,代码里也有“谁管谁”的边界
函数学到这里,还有一个特别容易让人混乱、但又特别关键的点,就是变量作用域。
num1 = 10list1 = [1, 2, 3, 4, 5]deff():global num1 num1 = 20 list1[2] = 8 num2 = 30print(num2)
刚开始我最容易糊涂的,就是为什么有些变量在函数里能改,有些只能在里面用。
后来我才慢慢理顺:
- •
global 是在明确声明:这里我要用外面的那个变量
也正是从这里开始,我第一次明显感觉到,函数不只是把代码包起来,它还在帮你划边界。
哪些东西只在这里有效,哪些东西会影响到外面,不能稀里糊涂地混着来。
6. lambda、map、filter、reduce 让我看见,函数也可以短到像一个动作
学到匿名函数时,我的感觉很新鲜。
因为我第一次看到,函数不一定都要郑重其事地写很多行。
a = [1, 2, 3, 4, 5]print(list(map(lambda x: x ** 2, a)))print(list(filter(lambda x: x % 2, a)))
这时候函数更像一个临时的小动作。
只做一件很明确的事,用完就走。
而 map、filter、reduce 这些写法,也让我第一次真正感受到:
函数不只是被调用,它还能拿去“加工一组数据”。
比如:
这一步会让代码看起来比前面更抽象一点。
但它也在提醒我,函数本身已经可以当成一种处理工具去传递了。
7. “上台阶”这个例子让我第一次看见,函数还能去描述一种规律
再往后写到“上台阶”时,我会明显感觉到,函数已经不只是封装动作了。
deff(n):if n == 0:return0elif n == 1:return1elif n == 2:return2return f(n - 1) + f(n - 2)print(f(4))
这段代码第一次让我认真感受到“递归”是什么。
不是把一个题目从头算到尾。
而是把它拆回和自己同类的小问题里。
这种感觉很奇妙。
因为它不像前面那些例子那么直白。
但一旦想通,就会突然发现,函数原来不只是帮你复用代码,它还能帮你表达规律。
也正因为这样,我会更愿意把这个例子看成一次视角变化。
你不是只在写步骤,你开始在写结构了。
8. 名片管理系统让我第一次看见,函数终于把程序撑成了一个整体
真正让我彻底理解函数价值的,是名片管理系统这种小项目。
defnew_card(name, phone, qq, email): user = {'name': name,'phone': phone,'qq': qq,'email': email, } cards.append(user)returnTruedef show_card():for card in cards:print(card)
这时候我会很明显地感觉到,函数已经不再只是一个单独的知识点了。
它开始像程序的骨架。
新建名片,是一个函数。
展示名片,是一个函数。
查询名片,也是一个函数。
每个动作各管一段,主流程只负责调度。
也就是从这里开始,我第一次真正看懂:为什么代码一长起来,就一定要学函数。
因为没有函数,所有东西都会挤在一起;而有了函数,程序才会开始分工,开始成形。
9. 这一段真正补上的,是“函数”这件事的知识骨架
写到这里,我后来会把这一段的核心知识点总结成这几条:
- •
*args / **kwargs:让函数接收更灵活的输入
我觉得这一段特别重要。
因为它补上的,不只是几个语法点,而是一个更成熟的写代码方式:
把重复动作收起来,把复杂流程拆开,把每一段逻辑放到它该在的位置。
最后
如果让我用现在这套眼光回头看这一段,我会说:
函数真正改变我的,不只是让我少写了几遍重复代码。
而是我第一次开始理解,代码不是越多越厉害,真正重要的是你能不能把已经想清楚的东西整理好、命名好、反复稳定地用下去。
也就是从这里开始,我第一次觉得,程序终于有了结构感。
它不再只是很多句子堆在一起。
它开始像一个被搭起来的东西。
🌷🌷🌷
如果你也学到这里,最让你有感觉的是哪一刻?
是第一次写出有参数的函数,第一次看懂 return,第一次被作用域绕晕,还是第一次在小项目里发现“原来函数真的能把程序撑起来”?