函数
函数是什么:
编程中的函数和数学中的函数有一定的相似之处。
编程中的函数,是一段可以被重复使用的代码片段。
语法格式:
函数的定义:
(分配任务) define :定义
def(定义) +函数名+(形参列表):(形参列表中,可以有多个形参之间使用,分隔)
函数体 这一部分要带有一级缩进(带有缩进的代码,才是函数内部的语句)
return 返回值 (函数的返回值函数执行到return 就意味着执行完了,return 后面的值,就是函数的返回值,return语句并不是必须的,可以有,也可以没有)
函数的调用:
函数名(实参列表) 此处的实参个数要和形参的个数匹配。
返回值=函数名(实参列表),如果函数有返回值,那么需要这样写。
如果只是定义,而不去调用,则函数体里面的代码就不会执行。
python中要求,函数定义写在前面,函数调用写在后面,先定义后调用。
代码的警告和错误处理:
警告:提示你的代码可能存在问题,但是并不影响程序的编译运行。
这个警告的意思是函数名应该用小写,我们可以写成calc_sum,第二种方式则是点击这个忽略警告。
这个警告的意思是,期望有两个空行,而现在只有一个空行。空行是指这串代码和上一行代码的空行距离。函数定义后需要加两个空行。
这个警告是在函数的末尾应该加上一个空行。
PEP这是python里面一套非常流行的编程规范(也就是写代码的一些“软性要求”)
错误:代码中实打实的有问题
函数的参数:
再python中,只是要求个数,对类型没有要求。
也不是说随便传入啥类型都可以,只要保证传入的参数类型,再函数体里面能够支持对应的运算操作,即可。
函数的返回值:
函数的参数可以视为是函数的输入,则函数的返回值,就可以视为是函数的“输出”
在实际开发中,一般更倾向于第二种写法。
一个通用的编程原则:一个函数只做一件事,
第一个版本,既做了计算,又做了打印(和用户交互)
第二个版本,只是做了计算,不关心如何和用户交互。
一旦后续需要改变和用户交互的方式,第二种方式就更有优势(不必修改代码了)
当前是通过控制台和用户交互的
让逻辑和交互/界面分离(进一步的好处,解耦合)
耦合:一个稍微复杂一些的程序,经常会涉及到很多个模块。
模块之间可能要进行交互。
交互就会带来耦合,当然希望通过良好的设计让耦合尽量低。
多个return语句:
python一次可以返回任意多个值和多元赋值
虽然现在返回了多个值,但是我只想用其中的一部分,不关注其他的,可以使用_来占位。
变量作用域:
函数里面的x,y和函数外面的xy不是同一变量,只不过名字恰好相同。
变量的作用域:一个变量名的有效范围是一定的,只在一个固定的区域内生效。
(函数内部的变量名,只能在函数内部生效,出了函数,就无效了,函数内部和外部是可以使用同名的变量的,虽然变量名相同,但是是不同的变量)
全局变量,是在整个程序中都有效的。(在函数外面)
局部变量,只是在函数内部有效的。(在函数里面)
函数里面也是可以使用全局变量的
在函数里尝试读取全局变量,是可以的,当函数中尝试访问某个变量的时候,会先尝试在局部变量中查找,如果找到,就直接访问,如果没找到,就会往上一级作用域中查找,test上一级就是全局了。
如何使用这个函数把全局变量x给改成20呢?
这里我们需要运用到global关键字,如果没有global,此时就会把x=20当做是在函数内部创建了一个局部变量x,而实际上是要修改全局变量x,为了让函数里面知道x是个全局变量,就使用global关键字声明一下。
函数的链式调用和嵌套调用:
链式调用:用一个函数的返回值,作为另一个函数的参数。链式调用,是先执行()里面的函数,后执行外面的函数。换句话说,调用一个函数,就需要先对他的参数求值。(链式调用的时候不要嵌套的太深,影响可读性)
嵌套调用:一个函数函数体内部,还可以调用其他函数
有的函数变量虽然同名,但是是不同变量,属于不同的函数作用域。
每个变量也是保存在各自的栈帧中的。变量本质就是一块内存空间。
函数递归:
就是一个函数自己调用自己。
以下是求5的阶乘:
n是函数形参,形参相当于函数的局部变量,局部变量在函数自己的栈帧上的,n=4时,虽然两个函数的局部变量名相同,但是是不同的栈帧,是不同的内存空间,也就是不同的变量了。
可借助调试器进行逐步运行。
递归代码有两个要素:
1,递归结束条件
2,递归的递推公式
递归的缺点:
1,执行的过程非常复杂,难以理解
2,递归代码容易出现栈溢出的情况的
3,递归代码一般都是可以转换成等价的循环代码的,并且,循环的版本通常运行速度要比递归的版本更有优势(函数调用也是有开销的)
递归的优点:
代码非常简洁,尤其是处理一些“问题本身就是通过递归的方式定义的”。
参数默认值:
python中的函数,可以给形参指定默认值。
带有默认值的参数,可以在调用的时候不传参。
形参的默认值,带有默认值的形参,就可以在调用函数的时候,不必传参
(要求带有默认值的形参,得在形参列表的后面,而不能在前面或者中间,带有多个默认参数的形参,这些都得放在后面)
关键字参数:按照形参的名字来进行传参。
在调用函数的时候,需要给函数指定实参,一般情况下是按照形参的顺序,来依次传递实参的,但是我们也可以通过关键字参数来调整这里的传参次数,显示指定当前实参传递给哪个形参。
非常明显的告诉程序猿,你的参数要传给谁。可以无视形参和实参的顺序。
(位置参数和关键字参数,还能混着用,只不过混着用的时候要求位置参数在前,关键字参数在后)