函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。函数能提高应用的模块性,和代码的重复利用率。你已经知道Python提供了许多内建函数,比如print()。但你也可以自己创建函数,这被叫做用户自定义函数。
你可以定义一个由自己想要功能的函数,以下是简单的规则:
1、定义一个无参函数
def hello():
print("hello")
hello()
hello这个函数后面没有参数,我们称之为无参函数,
2、定义一个有参函数
def fun1(name):
print("hello %s" %(name))
fun1("baozi")
fun1这个函数我们称为有参函数,在函数名后括号的参数,定义函数时的变量称为形式参数,变量名可以任意起,只是起到传递参数的作用;但当我们调用这个函数时,我们把“baozi”称为实参,调用函数时的参数称为实参,该参数必须是实际存在的,此时name = “baozi“
1、函数调用时一般有返回值;如果没有返回值时, python中默认返回None;例:我们定义一个hello函数,当我们运行并打印hello函数时,注意:“hello”并不是返回值,这是我们为了演示函数运行效果在函数内部打印的一条字符串,由于没有使用return返回值语句,python默认返回None。
下面是我们同一个函数,有return返回值的;
注意: return 返回可以是表达式、函数、变量(一个变量或多个变量)
2、return的应用
还记得前面我们学过if语句用来判断学生成绩:100~90为A;90~80为B;80~70为C;其余的为D;请用户输入一个分数来判断学生的成绩等级,今天我们就用函数来写:
我们来分析上面两个函数:
我们定义了两个函数,第一个student_leve 函数用来评定分数等级,需要一个参数来接收学生成绩,得到成绩以后通过if判断语句,来给出返回值‘A’‘B’‘C’‘D’;下面的main函数为我们的主函数,在这之前我们要导入random模块(此模块为产生随机数,我们定在1~100之间的随机数);通过for循环,我们一共产生10个随机数,并把值传给参数score,调用student_leve 函数;最后打印出成绩和等级。
3、 python中有一个叫None的特殊常量
对于初始化数据很有用,注意以下几点:
1)None是一个特殊的常量。
2)None和False不同。
3)None不是0。
4)None不是空字符串。
5)None和任何其他的数据类型比较永远返回False。
6)None有自己的数据类型NoneType。
7)你可以将None复制给任何变量,但是你不能创建其他NoneType对象。
例:比较列表中的最大值、最小值、和平均数?
这里我们要先介绍python中非常好用的:数值比较函数max(最大值)、min(最小值),他们可以自动比较列表等里面数字的大小;我们这里的返回值有三个,分别为最大值、平均值、最小值,当系统发现我们有多个返回值时,系统会自动把这些返回值封装为一个元组,我们看到这串列表的最大值为55,平均值为23.0,最小值为1,并且返回值的类型为元组(tuple)
函数的参数类型可分为:必选参数、默认参数、可变参数(不定长参数)、关键字参数、组合参数,总共5种。
例:当我们的形参为三个变量时,那我们调用函数时也需要传入三个值,否则系统会报错
我们,求x,y,z,三个值的和?
有三个变量相对应我们在传参时也应当传入三个值,分别与x,y,z相对应,否则系统会报错。如下:类型错误,缺少一个需要的位置参数‘z’。
默认参数:当我们在定义形参时,给变量默认输入一个值,当没有对应的实参传入时,函数默认使用形参的默认参数。
例:如果只有一个时参时
当只有一个时参时系统会默认把实参传给没有默认值的形参,另一个参数为默认参数
例2:如果有两个参数时
当系统发现我们传入两个实参,与形参数量相同,则系统将会把默认参数的值覆盖,使用实参的值
1)、可变参数:又称为可变长参数, *变量名; *args, args实质是一个元组;定义一个形参,可以输入多个实参,并且不会报错。
例:
我们定义可一个函数,里面的形参为*args 它可以接收多个实参,当我们调用这个函数并且打印形参的类型时,我们看出为tuple类,系统自动把它封装为一个元组。
2)、上面我们输入的为字符串,很多时候我们都是以列表或集合的形式去输入的,当系统发现如果已经存在:列表或集合,但是要把列表的每一个元素作为参数, 可以直接*li进行解包;
**kwargs关键字参数; 接收的kwargs是字典类型;
例1:我们在调用函数时,实参为一对数值对keys--value;**kwargs的类型为一个字典
例2:
例3:综合练习:传入多个值给函数,
在Python中定义函数,可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,这5种参数都可以组合使用。但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数。
比如定义一个函数,包含上述若干种参数:
1、题目需求:
对于一个十进制的正整数, 定义f(n)为其各位数字的平方和,如:
f(13) = 1**2 + 3**2 = 10
f(207) = 2**2 + 0**2 + 7**2 = 53
下面给出三个正整数k,a, b,你需要计算有多少个正整数n满足a<=n<=b,
且k*f(n)=n
输入:
第一行包含3个正整数k,a, b, k>=1, a,b<=10**18, a<=b;
输出:
输出对应的答案;
范例:
输入: 51 5000 10000
输出: 3
2、题目要求:使用函数找出1~1000中的素数(质数定义为在大于1的自然数中,除了1和它本身以外不再有其他因数)
def zhishu(y):
for i in range(2,y):
if y % i ==0:
return y
for x in range(1,1000):
if x != zhishu(x):
print(x)
3、Collatz序列
编写一个名为collatz()的函数,它有一个名为number的参数。如果参数是偶数,那么collatz()就打印出number//2,并返回该值。如果number是奇数,collatz()就打印并返回3*number+1。然后编写一个程序,让用户输入一个整数,并不断对这个数调用collatz(),直到函数返回值1(令人惊奇的是,这个序列对于任何整数都有效,利用这个序列,你迟早会得到1!既使数学家也不能确定为什么。你的程序在研究所谓的“Collatz序列”,它有时候被称为“最简单的、不可能的数学问题”)。
例:输入:3
输出:10、5、16、8、4、2、1
def collatz(number):
if number % 2 == 0:
return number // 2
else:
return 3 * number + 1
def main():
num = int(input('Num:'))
while True:
if collatz(num) == 1:
print(1)
break
else:
num = collatz(num)
print(num)
main()
作用域分为:
1)局部作用域
2)全局作用域
回顾之前学过的知识,我们学函数的时候,函数是个单独的作用域,Python中没有块级作用域,但是有局部作用域;看看下面的代码
def func():
name = "lzl"
print(name)
我们发现运行这段代码系统会报错,提醒我们没有定义这个变量,我相信这个大家都能理解,name变量只在func()函数内部中生效,所以在全局中是没法调用的;我们试着去改改这段代码;
由此我们就能区分出,什么是局部变量,name只在函数内有作用,当函数运行结束后这个变量就会被系统自动释放掉。
通过上面的实验,我们能看出num=2是定义在函数内部的变量,根据上面的例子我们在运行程序时应该会报粗,但是没有;由此我们看到了global关键字,把局部变量变为全局变量,所以我们在运行程序时自然不会报错。
上面我们都只是定义了一个函数一个变量,那么当我们定义多个函数但只有一个变量时系统会去那里寻找函数对应的变量呢?
举个简单的例子:
name = "lzl"
def f1():
print(name)
def f2():
name = "eric"
return f1()
f2()
请问输出结果为什么呢?lzl ? eric ?
分析一下:我定义了一个全局变量name,当我们调用f2时,f2中的name并没有显示出来,因为f2函数的返回值为f1函数,自然的当f2运行结束后会到f1函数,所以输出的结果自然为‘lzl‘;
如果你觉得上面我说的不够清楚,请你接着往下看:
name = "lzl"
def f1():
print(name)
def f2():
name = "eric"
return f1
ret = f2()
ret()
执行结果为“lzl”,分析下上面的代码,f2()执行结果为函数f1的内存地址,即ret=f1;执行ret()等同于执行f1(),执行f1()时与f2()没有任何关系,name=“lzl”与f1()在一个作用域链,函数内部没有变量是会向外找,所以此时变量name值为“lzl”