Frank the Obscure 无名的弗兰克

函数与参数


函数

函数是什么? 函数的功能, 可以概括为”做一件事情”.

  • print() 做了一件事情: 把想要打印的内容打出来
  • a + b 做了一件事情: 得到 a+b, 再返回这个值

函数之间可以有嵌套和互相引用:

  • print(a+b) 就是先返回 a+b, 再把这个值打印出来.

函数不仅在程序设计之中有用, 在现实生活中, 我们也可以把自己的行动抽象为”函数”.

  • 签字 做了一件事情: 把自己的名字写到纸上, 返回一张有签字的纸
  • 签三份合同 做了一件事情: 把自己的名字写到合同上, 重复三次

函数的输入和输出 (i/o)

函数有很多种功能, 但我们将函数进行抽象之后可以发现, 函数是个”黑盒子”, 一端是输入, 一端是输出. 这也是很多编程流程设计的”从上至下”的思路: 先将任务从最高的层次分解, 再设计各个层次间的输入输出接口(API).

因此, 一个函数的注释应当包括这三方面:

  • 函数的功能
  • 函数的输入
  • 函数的输出

此外, 如果两个函数在任何情况下的输入和输出一致, 那么它们在功能上完全等价. (不过可能会有算法时空效率等方面的不同)

参数化

很多时候我们可以发现, 很多函数在功能上有类似的地方:

  • print(a+b)print(a-b) 的输入都是 a 和 b, 输出都是一个打印的结果; 但输出的运算符不同.
  • 签字签十遍字的输入都是名字, 输出都是对应的文档; 但输出的次数不同.

机智的人们想到, 如果把步骤中相同或者不同的部分抽象出来, 就可以减少很多重复劳动了.

  • print(a, b, operator) 增加了参数 operator, 我们就可以把函数中不同的运算符通过一个参数表达, 从而复用了函数主体的代码.
  • 签字(次数) 增加了参数 次数, 把两个函数中共同的部分 签字 表达出来, 也将不同的部分 次数 用参数抽象, 实现复用.

以上的结论十分平凡, 也不难理解.

但在编程实践之中, 代码的抽象程度对代码的可读性, 可维护性, 健壮性等方面都有很大影响.

  • 相近的函数
  • 参数化之后, 可能代码的健壮性处理也会变得复杂或简单(都有可能, 根据实际需要处理的不同 io)

那么, 什么是合适的函数呢? 函数抽象到什么程度会比较合适?

我的理解, 这个问题可能要考虑以下几个方面:

  • 抽象层次过深, 可能导致理解困难
  • 抽象层次过浅, 每个函数做的事情太多, 不便于代码的复用.

“高内聚, 低耦合” 是函数设计的指导思路.

此外, 函数设计不必太追求”一步到位”, 更多的时候, 我们可以先用比较少的精力完成雏形, 让代码能够跑起来. 再根据实际中的反馈调整代码的设计.


Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.

上一篇 Jupyter notebook

下一篇 chaos to MoinMoin

Comments