首页 > 技术文章 > python 之 函数 基础

mylu 2019-06-07 21:48 原文

为什么要有函数?什么是函数? 1、组织结构不清晰,可读性差 2、代码冗余 3、管理维护的难度极大,扩展性

具备某一个功能的工具就是程序的中函数 ​ 事先准备工具的过程----》函数的定义 ​ 拿来就用----》函数的调用

所以函数的使用必须遵循:先定义,再调用

注意:没事先定义函数而直接调用,就相当于在引用一个不存在的变量名

5.1 函数定义和调用结构

定义阶段:在定义阶段只检测语法,不执行函数体代码
调用阶段:根据函数名找到函数的内存地址,然后执行函数体代码

1、语法 函数定义阶段
def 函数名(参数1,参数2,...):              #def:定义函数的关键字
      文档描述                          #函数名:是用来调用函数的, 函数名的命名必须能反映出函数的功能
    代码1                              #文档描述:推荐写上,来增强函数的可读性
    代码2                              #代码块:函数的功能实现代码
    代码3
    return#return:函数的返回值
1.1 调用阶段:函数名加括号就是在调用函数
def foo():
     print('from foo')
     bar()
foo()
2 定义函数的三种类型:
2.1 有参函数:参数是函数体代码用来接收外部传入值的
def max2(x,y): #x=100,y=101
     if  x > y:
         print(x)
     else:
         print(y)
​
 max2(100,101)
2.2 无参函数:当函数体的代码逻辑不需要函数的调用者掺入值的情况下,就无参
def func():
     print('----------------------')
     print('---soft run-----------')
     print('----------------------')
​
 def interactive():
     name=input('username>>: ').strip()
     pwd=input('password>>: ').strip()
     print(name,pwd)
2.3 空函数:函数体为pass
def auth():
    这是一个认证功能
    :return:
    pass
def put():
    上传功能
    :return:
    pass
def get():
    下载功能
    :return:
    pass
def ls():
    list contents
    :return:
    pass

5.2 函数返回值

什么时候应该有返回值: 函数体代码运行完毕后需要有一个返回结果给调用者

返回值有三种形式:
1 没有return,返回值None
 def func():
     pass
 res=func()
 print(res)
​
2 return后跟一个值,返回该值本身
 def func1():
     return 1
 res=func1()
 print(res)
​
3 return可以逗号分隔,返回多个值,会返回一个元组给调用者# (1, 2, [1, 2, 3])
 def func2():
     return 1,2,[1,2,3]
 res=func2()
 print(res)

return注意点: 1、return返回值的值,没有类型限制 2、return是函数结束的标志,函数内可以写多个return,但执行一次,函数就立刻结束,并把return后的值作为本次调用的返回值

def func3():
    print('first')
    return 1
    print('second')
    return 2
    print('third')
    return 3
res=func3()
print(res)

5.3 函数参数

5.31 形参与实参

1、形参与实参是什么? 形参(形式参数):指的是在定义函数时,括号内定义的参数,形参其实就变量名 实参(实际参数),指的是在调用函数时,括号内传入的值,实参其实就变量的值

#x,y是形参
def func(x,y): #x=10,y=11
    print(x)
    print(y)
#10,11是实参
func(10,11)

2、注意: 实参值(变量的值)与形参(变量名)的绑定关系只在函数调用时才会生效/绑定,在函数调用结束后就立刻解除绑定

5.32 位置参数

位置参数 位置即顺序,位置参数指的就是按照从左到右的顺序依次定义的参数

1 在定义函数时,按照位置定义的形参,称为位置形参
def foo(x,y,z):
    print(x,y,z)
#注意:
#位置形参的特性是:在调用函数时必须为其传值,而且多一个不行,少一个也不行
 

2 在调用函数时,按照位置定义的实参,称为位置实参
#注意:位置实参会与形参一一对应

5.33 关键字参数

1、什么是关键字参数: 在调用函数时,按照key=value的形式定义的实参,称为关键字参数

def foo(x,y,z):
    print(x,y,z)
foo(y=2,x=1,z=3)

注意: 1、相当于指名道姓地为形参传值,意味着即便是不按照顺序定义,仍然能为指定的参数传值

2、在调用函数时,位置实参与关键字实参可以混合使用,但必须必须遵循形参的规则

def foo(x,y,z):
    print(x,y,z)
foo(1,z=3,y=2)
# foo(1,z=3)

3、不能为同一个形参重复传值

def foo(x,y,z):
    print(x,y,z)
foo(1,x=1,y=3,z=2)

4、位置实参必须放到关键字实参的前面

def foo(x,y,z):
    print(x,y,z)
foo(1,y=3,z=2)

5.34 默认参数

在定义阶段,已经为某个形参赋值,那么该形参就称为默认参数 注意: 1 定义阶段已经有值,意味着调用阶段可以不传值

 def register(name,age,sex='male'):
     print(name,age,sex)
 register('egon',18,)                           # egon 18 male
 register('alex',73,'female')                    # alex 73 female
 register('wxx',84,)                            # wxx 84 male

2 默认形参必须在位置参数的后面

def func(x,y=1): 
    pass

3 默认参数的值只在定义阶段赋值一次,也就是说默认参数的值在定义阶段就固定死了

m=10
 def foo(x,y=m):
     print(x,y)
 m='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
 foo(1)                 # 1 10 
 foo(1,11)              # 1 11

4 记住:默认参数的值应该设置为不可变类型

def register(name,hobby,l=[]): # 列表 可变数据类型
     l.append(hobby) 
     print(name,l) 
register('wxx','play')          #   wxx ['play']
register('alex','read')         #   alex ['play', 'read']
register('egon','music')        #   egon ['play', 'read', 'music']
def register(name,hobby,l=[]): # 列表 可变数据类型
     l.append(hobby) 
     print(name,l) 
register('wxx','play',[])       # wxx ['play']
register('alex','read',[])      # alex ['read']
register('egon','music',[])     # egon  ['music']
def register(name,hobby,l=None):
    if l is None:
        l=[]
    l.append(hobby) 
    print(name,l) 
register('wxx','play')  # wxx ['play']
register('alex','read') # alex ['read']
register('egon','music') # alex ['music']

应用: 对于经常需要变化的值,需要将对应的形参定义成位置形参

对于大多数情况值都一样的情况,需要将对应的形参定义成默认形参

5.35可变参数

什么是可变长度参数 可变长度指的参数的个数可以不固定,实参有按位置定义的实参和按关键字定义的实参, 所以可变长的实参指的就是按照这两种形式定义的实参个数可以不固定,然而实参终究是要给形参传值的 所以形参必须有两种对应的解决方案来分别处理以上两种形式可变长度的实参,形参: * 、**

1.形参里包含*与**

* 会将溢出的位置实参全部接收,然后保存成元组的形式赋值给args
def foo(x,y,z,*args): #args=(4,5,6,7,8)
    print(x,y,z)
    print(args)
foo(1,2,3,4,5,6,7,8,)
** 会将溢出的关键字实参全部接收,然后保存成字典的形式赋值给kwargs
 def foo(x,y,z,**kwargs): # kwargs={'c':3,'a':1,'b':2}
     print(x,y,z)
     print(kwargs)
 foo(x=1,y=2,z=3,a=1,b=2,c=3)

2.实参里包含*与**

一旦碰到实参加*,就把该实参的值打散
 def foo(x,y,z,*args): #args=([4,5,6,7,8],)
     print(x,y,z)
     print(args)
 foo(1,2,3,*[4,5,6,7,8]) #foo(1,2,3,4,5,6,7,8)
 foo(1,2,3,*(4,5,6,7,8)) #foo(1,2,3,4,5,6,7,8)
 foo(1,2,3,*'hello') #foo(1,2,3,'h','e','l','l','o')
def foo(x,y,z):
     print(x,y,z)
 foo(*[1,2,3]) #foo(1,2,3)
 foo(*[1,2,3,4]) #foo(1,2,3,4) #报错
 foo(*[1,2,]) #foo(1,2,) #报错
一旦碰到实参加**,就把该实参的值打散
def foo(x,y,z,**kwargs):
    print(x,y,z)
    print(kwargs)
foo(1,2,3,**{'a':1,'b':2}) #foo(1,2,3,b=2,a=1)
def foo(x,y,z):
    print(x,y,z)
foo(1,**{'z':3,'y':2}) #foo(1,z=3,y=2)
foo(1,**{'z':3,'y':2,'x':111}) #foo(1,z=3,y=2,x=111)        # 报错,x重复赋值

*,** 组合使用

def index(name,age,gender):
    print('welcome %s %s %s' %(name,age,gender))
​
def wrapper(*args,**kwargs): #args=(1,2,3),kwargs={'x':1,'y':2,'z':3}
    print(args)
    print(kwargs)
    index(*args,**kwargs)       # index(*(1,2,3), **{'x':1,'y':2,'z':3}) 
                              # index(1,2,3,z=3,y=2,x=2)
wrapper(1,2,3,x=1,y=2,z=3)      # 报错
​
wrapper(name='egon',age=18,gender='male') # welcome egon 18 male
wrapper('egon',age=18,gender='male')
wrapper('egon',18,gender='male')
wrapper('egon',18,'male')

推荐阅读