函数

什么是函数

函数是可以重复执行的语句块,可以重复调用并执行函数的面向过程编程的最小单位。

函数的作用:

  • 函数用于封装语句块,提高代码的重用性,定义用户级别的函数、提高代码的可读性和易维护性。

函数的语法:

def 函数名(形参列表):
	语句块

作用:创建一个函数,将语句块打包,用函数名绑定,用来调用

说明:函数名的命名规则与变量名的命名规则相同(必须为标识符),函数名是一个变量,它用来绑定函数。函数有自己的命名空间,函数外部不可以访问函数内部的变量,函数内部可以访问函数外部的变量,但不能对外部变量赋值。语句块部分不能为空,如果为空需要填写pass语句

函数如果不需要传入参数,形参列表可以为空。

例子:

#此示例示意用def语句来定义函数
 def say_hello():
	print('hello world')
	print('hello 中国')

函数调用

语法:

函数名(实际调用传递参数)

说明:函数调用是一个表达式,如果函数内部没有return语句,函数执行完毕后返回None对象的引用

例子:

def say_hello():
	print("hello world")
    print("hello 中国")
#函数调用第一次
say_hello()
#函数调用第二次
say_hello()
#此示例示意用def语句定义函数
#函数外部的变量访问不了函数内部的变量
def say_hello():
    a = 100
    print("内部a是:",a)
say_hello()
#定义一个有参数的myadd函数
def myadd(a,b):
    print(a+b)
myadd(1,2)
myadd([1,2,3],[4,5,6])

return语句

语法:

return [表达式]
注释:[]代表其中的内容可以省略

作用:用于函数中,结束当前函数的执行,返回到调用该函数的地方,同时返回一个对象的引用关系

说明:

  • return语句后面的表达式可以省略,省略后相当于return None
  • 函数内部没有return语句的,则该函数执行完最后一条语句后返回None

练习:

1.写一个函数mymax,实现返回三个最大的值

如:def mymax(a,b,c):

……….

print(mymax(1,2,3))#3

print(mymax(“ABC”,“abc”,“123”))#abc

#小白写法
def mymax(a,b,c):
    return max(a,b,c)
print(mymax(1,2,3))
print(mymax("ABC","abc","123"))
#经典写法
def mymax(a,b,c):
    zuida = a
    if b > zuida:
        zuida = b
    if c > zuida:
        zuida = c
	return zuida
print(mymax(1,2,3))
print(mymax("ABC","abc","123"))

函数的传参

作用:把数据给函数

函数的形参

作用:接收函数调用传过来的数据

python函数的参数传递

传递方式:

  • 位置传参
  • 序列传参
  • 关键字传参
  • 字典关键字传参

位置传参

实际参数(实参)的对应关系与形式参数(形参)的对应关系是按照位置来依次对应的

示例:

# 此示例示意位置传参
def myfun(a, b, c):
    '''这是一个函数传参的示例'''
    print('a的值是:', a)
    print('b的值是:', b)
    print('c的值是:', c)

myfun(1, 2, 3)
myfun(4, 5, 6)
myfun("ABC", [1,2,3], (44,55,66))

说明:

实参和形参通过位置进行传递和匹配

实参的个数必须与形参的个数相同

序列传参

序列传参是指在函数调用过程中,用*(星号)将序列拆解后
按照位置进行传递的传参方式

示例:

# 此示例示意 序列传参
def myfun(a, b, c):
    '''这是一个函数传参的示例'''
    print('a的值是:', a)
    print('b的值是:', b)
    print('c的值是:', c)

L = [11, 22, 33]

# myfun(L[0], L[1], L[2])
myfun(*L)

# myfun(L)

说明:

序列传参时,序列拆解的位置将与形参一一对应

关键字传参

关键字传参是指传参时,按照形参名称给形参赋值
实参和形参按名称进行匹配

示例:

# 此示例示意 关键字传参
def myfun(a, b, c):
    '''这是一个函数传参的示例'''
    print('a的值是:', a)
    print('b的值是:', b)
    print('c的值是:', c)


myfun(c=33, b=22, a=11)
myfun(b=222, c=333, a=111)

说明:

可以不按照位置进行匹配
传参的顺序可以写乱

字典关键字传参

字典关键字传参是指实参为字典,将字典用**(双星号)拆解后进行关键字传参的传递方式

示例:

# 此示例示意 字典关键字传参
def myfun(a, b, c):
    '''这是一个函数传参的示例'''
    print('a的值是:', a)
    print('b的值是:', b)
    print('c的值是:', c)

d = {'a':100, 'c':300, 'b':200}

# myfun(a=d['a'], c=d['c'], b=d['b'])
myfun(**d)  # 等同于上面一条语句

# myfun(d)  # 出错

说明:

字典的键名和形参名必须一致
字典的键名必须符合标识符命名规则的字符串
字典的键名要在形参中存在

函数的综合传参

函数的传参方式在能确定形参能唯一匹配到相应实参的情况下可以任意组合
函数的位置传参要优先于关键字传参

示例:

def myfun(a, b, c):
        pass
    myfun(100, *[200, 300])
    myfun(100, *"BC")
    myfun(*"AB", 300)
    myfun(*[100], 200, *[300])
    myfun(100, c=300,b=200)
    myfun(a=100, 200, c=300)  # 错误的

    myfun(100, **{'c':300, 'b':200})
    myfun(100, **{'c':300}, b=200)
    myfun(100, b=200, **{'c':300})

函数的缺省参数

语法:

def 函数名(形参名1=默认实参1,形参名2=默认实参2,形参名3=默认实参3,.....)

作用:

让函数的调用者少传递参数来调用函数

示例:

# 此示例示意如何定义函数的缺省参数
def info(name, age=1, address="不详"):
    print(name, '今年', age,'岁,家庭住址:',
          address)

info("魏明择", 35, "北京市朝阳区")
info("Tarena", 15)
info("张飞")
# info()  # 出错

说明:

缺省参数必须自右至左一次存在,如果一个参数有缺省参数,则其右侧的所有参数必须有缺省参数
缺省参数可以有0个、一个或多个,甚至全部都有缺省参数

例子:

def fn(a,b=10,c):  #错误
    pass
def fn(a=0,b=None,c=False): #正确
    pass

函数的可变实参和不可变实参的传递

示例:

# 在函数内部对变量赋值是在函数内部创建新的局部变量
# 此赋值语句不会改变外部变量的绑定关系 
L = [1, 2, 3]
def f1(L):
    L = [4, 5, 6]  # 赋值语句的作用是创建和或改变变量的绑定关系
    print(L)  # [4, 5, 6]

f1(L)
print(L)  # [1, 2, 3]
L = [1, 2, 3]
def f1(L):
    # L = [4, 5, 6]  # 赋值语句的作用是创建和或改变变量的绑定关系
    L.append("ABC")
    print(L)  # [1, 2, 3, "ABC"]

f1(L)
print(L)  # [1, 2, 3, "ABC"]

说明:

当一个可变通过函数实参传入函数内时,在函数内可以通过局部变量来操作可变对象(列表,字典,集合...)

面试题:

#运行以下程序的结果是什么?为什么?
L = [1,2]
def fn(a,lst=[])
	lst.append(a)
    print(lst)
fn(3,L)  #[1,2,3]
fn(4,L)  #[1,2,3,4]
#####################
fn(5)	#[5]
fn(6)   #[5,6]
fn(7)	#[5,6,7]

函数形参的定义方式

  • 位置形参
  • 星号元组形参
  • 命名关键字形参
  • 双星号字典形参

位置形参

语法:

def 函数名(形参变量1,形参变量2,....):
语句块

星号元组形参

语法:

def 函数名(*元组形参名):
	语句块

作用:

收集多余的位置传参

说明:

元组形参名一般命名为'args'
*元组形参一个函数只能有一个

示例:

# 此示例示意星号元组形参
def func(*args):
    print("实参的个数是:", len(args))
    print("args=", args)

func()  # 无参
func(1,2,3,4)
func(1, 2, 3, 4, 5, 6, 7, 8)
s = "ABCDE"
func(*s)  # 等同于func('A', 'B', ....)
func(a=100, b=200)  # 出错

命名关键字形参

语法:

def 函数名(*,命名关键字形参1,命名关键字形参2,....):
	语句块
或
def 函数名(*args,命名关键字形参1,命名关键字形参2,....):
	语句块

作用:

强制所有的命名关键字形参都必须用关键字传参或字典关键字传参

示例:

# 此示例示意命名关键字形参
def func(a, b, *, c, d):
    print(a, b, c, d)

# func(1, 2, 3, 4)  # 传参失败
func(1, 2, c=30, d=40)
func(a=10, b=20, c=30, d=40)
func(1, 2, **{'d':400, 'c':300})

双星号字典形参

语法:

def 函数名(**字典形参名):
	语句块

作用:

收集多余的关键字传参

示例:

# 此示例示意双星号字典形参
def func(**kwargs):
    print("关键字传参的个数是:", len(kwargs))
    print('kwargs=', kwargs)

func(name="隔壁老王", age=35, address="朝阳区")

def func(*,a, b, **kwargs):
    print("关键字传参的个数是:", len(kwargs))
    print('kwargs=', kwargs)

func(a=1, b=2, c=3, d=4)

说明:

字典形参名一般命名为:'kwargs'
一个函数内字典形参最多只有一个

函数的形参说明:

  • 位置形参,缺省参数,星号元组形参,双星号字典形参可以混合使用
  • 函数形参自左至右的定义顺序为:
  • 位置形参
  • 星号元组形参
  • 命名关键字形参
  • 双星号字典形参

示例:

def fn(a, b, *args, c, **kwargs):
	pass
fn(1, 2, 3, 4, c=30, d=40, e=50)

函数的不定长参数

  • 星号元组形参
  • 双星号字典形参

用不定长参数可以接收任意的传参

如:

def fn(*args,**kwargs):
	print(*args,**kwargs)

全局变量和局部变量

局部变量

  • 定义在函数内部的变量称为局部变量(函数的形参也是局部变量)
  • 局部变量只能在函数内部使用
  • 局部变量在函数调用时才能创建,在函数调用之后会自动销毁

全局变量

  • 定义在函数外部的变量称为全局变量
  • 全局变量所有的函数都可以直接访问(但函数内部不能将其直接复制)

说明:

函数内部复制语句不会对全局变量造成影响

函数变量

函数名是变量,它在创建函数时绑定一个函数

示例:

# 此示例示意函数名为变量,可以其它变量来绑定同一个函数
def f1():
    print("f1函数被调用!")

f2 = f1  # 看清楚,不是 f2 = f1()  <<===没括号

f2()  # 调用哪儿个函数?
f1()
def f1():
    print("f1函数被调用!")

def f2():
    print("f2函数被调用!")

f1, f2 = f2, f1  # 交换两个函数名变量的绑定关系

f1()  # 请问调用谁?

说明:

一个函数可以作用另一个函数的实参传递
可以把一个函数给另一个函数,另一个函数的形参变量将
绑定实参函数

函数可以作为另一个函数的返回值

示例:

def f1():
    print("f1")

def f2():
    print("f2")

def get_fx(n):
    if n == 1:
        return f1
    elif n == 2:
        return f2
fx = get_fx(1)
fx()  # 调用f1
fx = get_fx(2)
fx()  # 请问调用谁?

函数的嵌套定义

函数嵌套定义是指一个函数里用def 语句来创建其他函数的情况

示例:

# 此示例示意在函数内部创建函数,在函数内部来调用
def fn_outer():
    print("fn_outer被调用")

    def fn_inner():
        print("fn_inner被调用")

    fn_inner()
    fn_inner()
    fn_inner()

    print("fn_outer调用结束")

fn_outer()
# fn_inner()  # 调用出错