在开发程序时,需要多次使用某块代码,这时可以将这部分代码独立为一个模块,这便是函数。函数可以提高编码的效率和代码复用。一个类中函数名不能重复使用。
def 函数名(): 代码逻辑
例:求0~100累加和
def sum(num): result = 0 while num > 0: result += num num -= 1 return result print("---调用sum函数---") a = sum(100) print("求0到100之和:%d"%a) 输出: ---调用sum函数--- 求0到100之和:5050
局部变量
- 局部变量,就是在函数内部定义的变量
- 不同的函数,可以定义相同的名字的局部变量,但是相互不会产生影响
- 局部变量的作用,为了临时保存数据需要在函数中定义变量来进行存储,这就是它的作用
def test1(): avr = 100 print("test1中的avr=%d"%avr) def test2(): avr = 300 print("test2中的avr=%d"%avr) test1() test2() 输出: test1中的avr=100 test2中的avr=300
全局变量
- 在函数外边定义的变量叫做
全局变量
- 全局变量能够在所有的函数中进行访问
- 如果在函数中修改全局变量,那么就需要使用
global
进行声明,否则出错:UnboundLocalError: local variable 'a' referenced before assignment - 如果全局变量的名字和局部变量的名字相同,那么使用的是局部变量的
a = 100 #定义全局变量 def test1(): global a print('test1修改之前a=%d'%a) a = 188 print('test1修改之后a=%d'%a) def test2(): print("---test2中---a=%d"%a) #调用函数 test1() test2() 输出: test1修改之前a=100 test1修改之后a=188 ---test2中---a=188
对于不可修改的全局变量而言,使用global来声明其实在是修改其内存中的指向,即修改了地址。
对于可变类型(列表、字典)的全局变量而言,因为其指向的数据是可以修改的,所以不必用global声明,就可以修改。
函数常见的几种参数
- 缺省参数。调用函数时,缺省参数的值如果没有传入,则使用默认值;默认参数值一定要位于参数列表最后,否则报错
SyntaxError: non-default argument follows default argument
def printInfo(name,age = 18): print("name: ",name,end=" ,") print("age: ",age) printInfo(name="AOC") printInfo(age=18,name="Dail") #printInfo(age=18,"Dail") #SyntaxError: positional argument follows keyword argument # age是关键字参数,“Dail”是位置参数 输出: name: AOC ,age: 18 name: Dail ,age: 18
注:关键字参数必须跟在位置参数之后,因为Python函数解析参数时,按照顺序来的,必须先满足位置参数,再考虑其他可变参数。
- 不定长参数。在某些场景下函数处理参数可能比最初的要多,这些变化的参数叫不定参数,声明时不会命名。
def functionname([formal_args,] *args, **kwargs): "函数_不定长参数" pass return [expression]
*args存放所有未命名的变量参数,args为元组;**kwargs存放命名参数,kwargs为字典。
#可变参数 def fun(a,b,*args,**kwargs): "不定长参数函数" print("a = ",a) print("b = ",b) print("*args = ",args) print("**kwargs = ",kwargs) fun(1,2,3,4,'A',i=5,j=6,k=7) 输出: a = 1 b = 2 *args = (3, 4, 'A') **kwargs = {'i': 5, 'j': 6, 'k': 7}
- 引用参数。Python中的函数传递参数是引用传递,不是我们以为的值传递。对于不可变类型的变量而言,运算不会影响到变量自身。对于可变类型而言,在函数体中的运算可能会更改传入的参数变量。
#引用参数 def test(a): "---自增---" a += a print('调用时test---a=',a,'id(a)=',id(a)) num = 1 print("调用前id(num)=",id(num)) test(num) print("调用后id(num)=",id(num),"num = ",num) print('='*20,'可变类型参数') alist = ['1','2'] print("调用前id(alist)=",id(alist)) test(alist) print("调用后id(alist)=",id(alist),"alist = ",alist) 输出: 调用前id(num)= 10919328 调用时test---a= 2 id(a)= 10919360 调用后id(num)= 10919328 num = 1 ==================== 可变类型参数 调用前id(alist)= 140681290722120 调用时test---a= ['1', '2', '1', '2'] id(a)= 140681290722120 调用后id(alist)= 140681290722120 alist = ['1', '2', '1', '2']
递归函数
一个函数在其内部不停的调用自身,这便是递归函数。
def calNum(num): if num >= 1: result = num + calNum(num-1) else: result = 0 return result print("结果:",calNum(100)) 输出: 结果: 5050
匿名函数
用lambda关键词能创建小型匿名函数。这种函数得名于省略了用def声明函数的标准步骤。lambda函数的语法只包含一个语句,如下:
lambda [arg1 [,arg2,.....argn]]:expression #expression结果作为返回值
def test(a,b,func): result = func(a,b) return result num = test(10,40,lambda x,y:x+y) print("计算结果:%d"%num) 输出: 计算结果:50
eval() --内置函数
eval(expression, globals=None, locals=None) --- 官方文档中的解释是,将字符串str当成有效的表达式来求值并返回计算结果。globals和locals参数是可选的,如果提供了globals参数,那么它必须是dictionary类型;如果提供了locals参数,那么它可以是任意的map对象。
exp = input("输入一个表达式:") #exp为字符串 print("输出exp: ",exp) #eval将str解析为有效的表达式、并返回计算结果 print("eval输出结果: ",eval(exp)) 输出: 输入一个表达式:5*5 输出exp: 5*5 eval输出结果: 25
eval()滥用会有风险
Python作为动态语言,有时交互时需要用户输入一个表达式。如果用户输入:__import__('os').system('dir'),那么当前目录文件将全部暴露给用户,用户这时可以继续访问文件,甚至删除当前目录的文件。
规避方法:
1、自行写检查函数;
2、使用ast.literal_eval:自行查看DOCUMENT