Python——函数基础
函数是什么
它相当于一个独立的代码块,可以被重复使用,如果需要增加一个功能或者修改一个功能,只需要,增加或者修改函数即可。
函数分类
内置函数
python解释器已经为我们定义好的参数,比如:len(),sum(),max()等
自定义函数
根据自身的需求,自己定制的函数
定义函数
语法
def 函数名(参数1,参数2,参数3,...): '''注释''' 函数体 return 返回的值
一旦执行到return,整个函数就结束了。如果没有return,会默认返回None。return可以返回多个参数,这多个参数用元组封装。
定义函数的三种形式
#1、无参:应用场景仅仅只是执行一些操作,比如与用户交互,打印 #2、有参:需要根据外部传进来的参数,才能执行相应的逻辑,比如统计长度,求最大值最小值 #3、空函数:设计代码结构, 函数需要函数体,如果没有的话,会报错,这个时候可以写一个pass,这个就表示什么都不做。虽然看起来做的是一件没有用的事情,但是这样可以让程序运行起来。
有参、无参如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#定义阶段 def tell_tag(tag,n): #有参数 print(tag*n) def tell_msg(): #无参数 print('hello world') #调用阶段 tell_tag('*',12) tell_msg() tell_tag('*',12) ''' ************ hello world ************ ''' #结论: #1、定义时无参,意味着调用时也无需传入参数 #2、定义时有参,意味着调用时则必须传入参数 无参、有参
无参如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def auth(user,password): ''' auth function :param user: 用户名 :param password: 密码 :return: 认证结果 ''' pass def get(filename): ''' :param filename: :return: ''' pass def put(filename): ''' :param filename: :return: ''' def ls(dirname): ''' :param dirname: :return: ''' pass #程序的体系结构立见 空函数
定义阶段做的事情
只检查语法,不执行代码。也就是说:语法错误可以在函数定义的时候检测出来,而代码的逻辑错误只有在执行时才暴露。
如果函数名相同,后面定义的函数会覆盖前面的函数。
使用函数
使用的原则
函数使用的时候,要保证先定义,后调用
例子如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
函数即“变量”,“变量”必须先定义后引用。未定义而直接引用函数,就相当于在引用一个不存在的变量名 #测试一 def foo(): print('from foo') bar() foo() #报错 #测试二 def bar(): print('from bar') def foo(): print('from foo') bar() foo() #正常 #测试三 def foo(): print('from foo') bar() def bar(): print('from bar') foo() #会报错吗? #结论:函数的使用,必须遵循原则:先定义,后调用 #我们在使用函数时,一定要明确地区分定义阶段和调用阶段 #定义阶段 def foo(): print('from foo') bar() def bar(): print('from bar') #调用阶段 foo()
调用函数方式
1 语句形式:foo() 2 表达式形式:3*len('hello') 3 当中另外一个函数的参数:range(len('hello'))
函数嵌套
函数嵌套调用
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def max(x,y): return x if x > y else y def max4(a,b,c,d): res1=max(a,b) res2=max(res1,c) res3=max(res2,d) return res3 print(max4(1,2,3,4))
函数嵌套定义
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def f1(): def f2(): def f3(): print('from f3') f3() f2() f1()
函数特性
函数是第一类对象,即函数可以当作数据传递
比如:
#1 可以被引用 #2 可以当作参数传递 #3 返回值可以是函数 #3 可以当作容器类型的元素
例1:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def demo(): print("demo1") a = demo b = a b()
例2:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def foo(): print('foo') def bar(): print('bar') dic={ 'foo':foo, 'bar':bar, } while True: choice=input('>>: ').strip() if choice in dic: dic[choice]()
形参和实参
形参即变量名,实参即变量值,函数调用时,将值绑定到变量名上,函数调用结束,解除绑定
具体使用:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#1、位置参数:按照从左到右的顺序定义的参数 位置形参:必选参数 位置实参:按照位置给形参传值 #2、关键字参数:按照key=value的形式定义的实参 无需按照位置为形参传值 注意的问题: 1. 关键字实参必须在位置实参右面 2. 对同一个形参不能重复传值 #3、默认参数:形参在定义时就已经为其赋值 可以传值也可以不传值,经常需要变得参数定义成位置形参,变化较小的参数定义成默认参数(形参) 注意的问题: 1. 只在定义时赋值一次 2. 默认参数的定义应该在位置形参右面 3. 默认参数通常应该定义成不可变类型 #4、可变长参数: 可变长指的是实参值的个数不固定 而实参有按位置和按关键字两种形式定义,针对这两种形式的可变长,形参对应有两种解决方案来完整地存放它们,分别是*args,**kwargs ===========*args=========== def foo(x, y, *args): print(x, y) # 1 2 print(args) # (3, 4, 5) foo(1, 2, 3, 4, 5) ----------------------------------------------- def foo(x, y, *args): print(x, y) # 1 2 print(args) # (3, 4, 5) foo(1, 2, *[3, 4, 5]) ----------------------------------------------- def foo(x, y, z): print(x, y, z) # 1 2 3 foo(*[1, 2, 3]) ----------------------------------------------- def foo(*args, x, y): print(x, y) print(args) foo(1, 2, *[3, 4, 5]) # 报错 ===========**kwargs=========== def foo(x, y, **kwargs): print(x, y) # 1 2 print(kwargs) # {'c': 3, 'a': 1, 'b': 2} foo(1, y=2, a=1, b=2, c=3) ---------------------------------------------- def foo(x, y, **kwargs): print(x, y) # 1 2 print(kwargs) # {'c': 3, 'a': 1, 'b': 2} foo(1, y=2, **{'a': 1, 'b': 2, 'c': 3}) ----------------------------------------------- def foo(x, y, z): print(x, y, z) # 2 3 1 foo(**{'z': 1, 'x': 2, 'y': 3}) ===========*args+**kwargs=========== def foo(x, y, *args, **kwargs): print(x, y) # 1 2 print(args) # (3, 4, 5) print(kwargs) # {'c': 4, 'b': 3, 'd': 5} foo(1, 2, 3, 4, 5, b=3, c=4, d=5) ---------------------------------------------- *后定义的参数,必须被传值(有默认值的除外),且必须按照关键字实参的形式传递 def foo(x, y, *args, a=1, b, **kwargs): print(x, y) # 1 2 print(args) # (3, 4, 5) print(a) # 1 print(b) # 3 print(kwargs) # {'c': 4, 'd': 5} foo(1, 2, 3, 4, 5, b=3, c=4, d=5)
函数作用域
函数相当于一个封装好的盒子,里面可以定义局部变量,随着函数的调用和结束,其中的局部变量也随之建立和消亡。而且局部变量只能在该函数中有效。
上面说到过,函数可以嵌套使用,当一个函数内使用一个变量的时候,查找的原则是就近原则。也就是本函数有就使用本函数的,再到上级函数找,找到全局变量之后没有,再发现内置变量也没有的话就会报错。
例1:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
max=1 def f1(): max=2 def f2(): max=3 print(max) # 3 f2() f1() print(max) # 1 # 其中max=1属于全局变量,max=2和max3属于局部变量
当使用全局变量的时候,如果全局变量是可变类型的话,可以对其元素进行修改,如果是不可变类型则只能进行取值。
例如:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
a = [1, 2, 4, "5"] def demo(): a[3] = 5 print(a) # [1, 2, 4, 5] demo() print(a) # [1, 2, 4, 5]
global
当你要使用全局变量的时候可以用global。使用global声明后,可以对全局变量进行修改
例如:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
max=1 def f1(): max=2 def f2(): global max max = 9 print(max) # 9 f2() f1() print(max) # 9
当你先定义了局部变量再用global声明全局变量的时候就会报错
例如:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
max=1 def f1(): max=2 def f2(): max = 3 global max # 报错 max = 9 print(max) f2() f1() print(max)
在实际开发中其实不会产生这种问题,因为根据命名规范,全局变量要大写表示。
注:global可以直接找到全局变量,可以用nonlocal找到上级的变量,这个和global差不多,只不过它找的是上一级函数的