调用函数
函数名加括号即调用函数
定义阶段:在定义阶段只检测语法,不执行函数体代码
调用阶段:根据函数名找到函数的内存地址,然后执行函数体代码
定义阶段: def foo(): print('from foo')
soo() #函数只要在发生调用之前被定义就行了,变量必须要经过定义才能被引用。也就是说函数在定义阶段时可以写其他还没被定义的函数 def soo(): print('from soo') 调用阶段: foo() 执行结果: from foo from soo
结论:定义阶段函数foo与soo均无语法错误,而在调用阶段调用foo()时,函数foo与soo都早已经存在于内存中了,所以不会有任何问题
函数的返回值
函数体代码运行完毕后需要有一个返回结果给调用者。
1、没有return:默认返回None 2、只写return:只有结束函数体代码的效果,返回None 3、写return None: 与只写return的效果一样 4、return后跟一个值,返回该值本身 5、return可以用逗号隔开,返回多个值,返回的多个值存入一个元组返回 注意: 1.return返回值的值,没有类型限制,可以自己指定返回的数据类型 2.返回的值不能被修改 3.函数内可以写多个return,return执行一次,函数就立刻结束,并把return后的值作为本次调用的
函数参数详解一、 形参与实参
形参:即在定义函数时,括号内声明的参数。形参本质就是一个变量名,用来接收外部传来的值。
实参:即在调用函数时,括号内传入的值,值可以是常量、变量、表达式或三者的组合。
注意:在调用函数时,实参值(变量的值)会赋值给形参(变量名),两者的绑定关系只在函数调用时才会生效,在调用函数结束后就立刻接触绑定
1.1、参数的形式
1、位置参数:通过位置从左到右的顺序依次定义的参数
def foo(a,b) print(a,b) foo(1,2) 注意: 1、位置形参的特性是在调用函数时必须为其传值,而且多一个少一个都不行 2、位置实参与形参一一对应
2、关键字参数:在调用函数时,按照key=value的形式定义的实参,称为关键字参数
def foo(x,y,z): print(x,y,z)1 foo(x=1,y=2,z=3) 注意: 1、相当于指名道姓地为形参传值,意味着即便是不按照顺序定义,仍然能为指定参数传值 2、在调用函数时,位置实参与关键字实参可以混合使用,但关键字实参必须要放在位置实参后,不能为同一个形参重复传值
3、默认参数:在定义阶段,已经为某个形参赋值,那么该参数称为默认参数
注意: 1、定义阶段已经有值,意味着调用阶段可以不传值,但如果在实参的时候传入新参数,就会使用新参数 def register(name,age,sex='male'): print(name,age,sex) register('egon',18,'male') register('alex',73,'female') register('wxx',84,'male')
2、默认参数的值只在定义阶段赋值一次,也就是说默认参数的值在定义阶段就固定死了 #易错点 m = 10 def foo(x,y=m) print(x,y) m=111111 foo(1) >>>1,10 > 3、默认参数在传值的时候,不要将可变类型当作参数传值 def register(name,hobby,l=[]): l.append(hobby) print(name,l) register('egon','play') register('alex','AK') register('wxx','gun')
egon ['play']
alex ['play', 'AK']
wxx ['play', 'AK', 'gun']
def register(name,hobby,l=[]): l.append(hobby) print(name,l) register('egon','play',[]) #egon ['play'] register('alex','AK',[]) #alex ['AK'] register('wxx','gun',[]) #wxx ['gun'] def register(name,hobby,l=None): if l == None: l=[] l.append(hobby) print(name,l) register('egon','play') #egon ['play'] register('alex','AK') #alex ['AK'] register('wxx','gun') #wxx ['gun']
应用:对于经常需要变化的值,需要将对应的形参定义为位置形参,对于大多数值都一样的情况,需要将对于的形参定义成默认形参。
4、可变长参数:可变长指的是参数的个数可以不固定。实参有按位置定义的实参 和 按关键字定义的实参,所以可变长的实参指的就是按照这两种形式定义的实参个数可以不固定,然而实参终究是要给形参传值的,所以形参必须要有两种对应的解决方案来分别处理以上两种形式可变长度的实参
foo(1,2) foo(1,2,3) foo(1,2,3,4) foo(x=1,y=2) foo(x=1,y=2,z=3
形参包含*/**
*会将溢出的位置实参全部接受,然后保存成元组的形式赋值给args
def foo(x,y,z,*args): print(x,y,z) print(args) foo(1,2,3,4,5,6) >>>123 >>>(4,5,6)
**会将溢出的关键字实参全部接受,然后保存成字典的形式赋值**后面的变量中 def foo(x,y,z,**kwargs): print(x,y,z) print(kwargs) foo(x=1,y=2,z=3,d=4,f=5,e=6) >>>1 2 3 >>>{'d': 4, 'f': 5, 'e': 6}
实参里包含*/**
*:一旦碰到实参加*,打散你传入的容器类型 def foo(x,y,z,*args): print(x,y,z) print(args) foo(1,2,3,*[4,5,6]) #--->foo(1,2,3,4,5,6) >>>1 2 3 >>>(4, 5, 6)
**:一旦碰到实参加**,就把字典打散成关键字参数传入形参 #定义函数 def test(*args, **kwargs): print(args) print(kwargs) #定义一个元组和一个字典 tuple = (1,2,3,4,5) dict = {'a':1,'b':2,'c':3} #tuple和dict两个参数会作为一个元组传递给*args参数,而没有实参传递给**kwargs参数。 test(tuple,dict) >>>((1, 2, 3, 4, 5), {'a': 1, 'b': 2, 'c': 3}) >>>{} #打散传参 test(*tuple, **dict) #test(1,2,3,4,5,a=1,b=2,c=3) >>>(1, 2, 3, 4, 5) >>>{'a': 1, 'b': 2, 'c': 3}
组合使用:如果一个函数的形参为*args与**kwargs,那么代表该函数可以接收任何形式、任意长度的参数
def wrapper(*args,**kwargs): print(args) print(kwargs) wrapper(1,2,3,4,5,6,x=6666,y=2222) >>>(1, 2, 3, 4, 5, 6) >>>{'x': 6666, 'y': 2222
5、命名关键字参数(了解)
格式:在后面的参数都是命名关键字参数
特征:后定义的参数,必须被传值(有默认值的除外),且必须按照关键字实参的形式传递
def index(x, y, z, a=1, *args, b, **kwargs): print(x, y, z) print(a) print(args) print(b) print(kwargs) index(1, 2, 3,354353, 4342, 3213123, b=222, c=333, d=444) 输出结果: 1 2 3 354353 (4342, 3213123) 222 {'c': 333, 'd': 444}