一、 函数入门

1. 定义与调用

def 函数名(p1,p2,...pn):
    #可执行语句
    [return [返回值|表达式]]

举个栗子

def my_max(x,y):
    if x >= y:
        result=x
    else:
        result=y
    return result

#调用
result=my_max(5,10)
print(result)

#或者直接
print(my_max(5,10))

#也可以在调用时指定关键字
result=my_max(x=5,y=10)

#不推荐,很不规范
result=my_max(y=10,x=5) 
result=my_max(5,y=10)

函数参数可以带默认值,但带默认值的参数必须要在最后

def my_max(x,y=5):
    return x if x>=y else y

print(my_max(x=6)) #输出 6


#错误示例
def my_max(x=5,y):
    return x if x>=y else y

#报错
def my_max(x=5,y):
              ^
SyntaxError: non-default argument follows default argument

return可以返回多个值,可以用一个变量也可用对应数量变量接收返回值

def sum_and_cnt(mylist):
    sum=0
    cnt=len(mylist)
    for i in mylist:
        sum += i
    return sum,cnt

#调用
a_list=[2,5,8,9,3,9,1]
sum,cnt=sum_and_cnt(a_list)
print("sum = %d,cnt = %d" % (sum,cnt))   #输出 sum = 37,cnt = 7

#若用单个变量接收接收返回值,该变量会自动被封装为元组
result=sum_and_cnt(a_list)
print(result)                            #输出 (37, 7)

2. 为函数提供帮助文档

只要将一段字符串放在函数声明与函数体之间,这段字符串就会被当作帮助文档

可以通过help()函数及函数的__doc__属性查看函数帮助文档

def my_max(x,y):
    '''
    功能:输入两个数字,返回两个数间较大值。
    使用示例:print(my_max(5,10))
    '''

    #return后可为表达式(该注释不会显示在帮助文档中)
    return x if x>=y else y

#查看帮助文档
help(my_max)
#输出
my_max(x, y)
    功能:输入两个数字,返回两个数间较大值。
    使用示例:print(my_max(5,10))

print(my_max.__doc__)
#输出
功能:输入两个数字,返回两个数间较大值。
    使用示例:print(my_max(5,10))

3. 递归函数

调用函数自身,包含隐式的循环,但是效率通常不如循环

递归函数最经典的例子之一是求阶乘:f(0)=0,f(1)=1,f(n)=n*f(n-1)

def my_factorial(n):
    if n == 0:
        return 0
    elif n==1 :
        return 1
    else:
        return n*my_factorial(n-1)

print(my_factorial(10))  #输出 3628800

二、 深入参数

1. 支持“普通”参数收集的形参(个数可变的参数)

  • python中在参数前添加* 意味着该参数可接收多个参数值
  • “普通”是指这种形参代入值时不能使用关键字,只能按位置一一对应
  • 多个参数值被视为一个元组传入
  • python允许个数可变的形参处于形参列表的任意位置
  • 每个函数只能带一个支持“普通”参数收集的形参
def test(a,*b):
    print(a)
    print(b)

test(5,'ggd','424','fff',890)

#输出
5
('ggd', '424', 'fff', 890)

2. 支持“关键字”参数收集的形参

  • 在参数前添加** 代表该形参支持“关键字”参数收集 
  • “关键字”是指这种形参代入值时需要使用关键字,python会将关键字及其值以字典形式保存起来
  • 函数可同时包含一个支持“普通”参数收集的形参和一个支持“关键字”参数收集的形参
def test(a,*b,**c):
    print(a)
    print(b)
    print(c)

test(5,'b01','b02','b01',c1=1,c2=3,c3=3)

#输出(2为元组,3为字典)
5
('b01', 'b02', 'b01')
{'c1': 1, 'c2': 3, 'c3': 3}

3. 逆向参数收集

  • 在调用函数时,将列表、元组、字典等的值拆开传给函数形参(包括支持参数收集的形参)
  • 需要在传入的列表、元组参数前加一个*,在字典参数前加**
  • 字典需要以关键字参数形式传入
#将列表值拆给函数形参
def test1(name,age):
    print(name)
    print(age)

my_list=['Conan',7]
test1(*my_list)
#将元组值拆给支持参数收集的形参
def test2(name,*numbers):
    print(name)
    print(numbers)

my_tuple=(1,3,6,9,4,2)
test2('test2',*my_tuple)

#输出
test2
(1, 3, 6, 9, 4, 2)
#字典的逆向收集
def test3(book,price,type):
    print(book,"的价格为",price,"元;分类为",type)

my_dict={'book':'DB book','price':100,'type':'IT'}
test3(**my_dict)

#输出
DB book 的价格为 100 元;分类为 IT

4. 函数的参数传递机制

python中的参数传递机制均为“值传递”,即只是将形参副本传入参数,而形参本身不受任何影响

def test(i):
    i=100  #对i赋值100
    print("函数中i的值为",i)

i=50
test(i)
print("经过函数赋值后,i的值为",i)

#输出
函数中i的值为 100
经过函数赋值后,i的值为 50
#说明函数中修改的只是传入形参i的一个复制品,函数内的修改对形参i本身无影响

要想让函数修改某些数据,可将这些数据包装成列表、字典等可变对象作为参数传入,通过列表、字典的方法修改它们。注意这依然是“值传递”机制,只不过系统复制的是传入的引用参数,而非字典本身。

三、 变量作用域

1. 变量分类

  • 局部变量:在函数中定义的变量(包括参数)
  • 全局变量:在函数外、全局范围定义的变量,可被所有函数访问

2. 用于获取变量字典的工具函数

  • globals():返回全局范围内所有变量组成的“变量字典”,若修改返回的“变量字典”,会真正改变全局变量本身
  • locals():返回当前局部范围内所有变量组成的“变量字典”,若修改返回的“变量字典”,不会改变局部变量。若在函数外(全局范围内)调用,便相当于globals
  • vars(object):获取指定对象范围内所有变量组成的“变量字典”
def test():
    age=20
    #直接访问局部变量
    print(age) #20
    #通过局部函数访问变量字典
    print(locals())  #{'age': 20}
    # 通过局部函数访问变量字典的值
    print(locals()['age'])  #20
    # 通过局部函数修改变量字典的值
    locals()['age']=12
    #再次访问
    print(age)  #20

    #通过globals函数修改x全局变量
    globals()['x']=19

x=5
test()
y=20
print(globals())  #{'x': 19, 'y': 20}
#在全局范围内使用locals函数
print(locals())  #{'x': 19, 'y': 20}
#直接访问全局变量
print(x)  #19

# 通过全局函数访问变量字典的值
print(globals()['x'])  #19
# 通过全局函数修改变量字典的值
globals()['x']=39
print(x)  #39
# 在全局范围通过局部函数修改变量字典的值
locals()['x']=99
print(x)  #99

3. 局部函数

被放在函数体内定义的函数称为局部函数,它只在外层函数范围有效,但可以通过return返回值至外层函数

def my_math_func(type,value):
    #求平方
    def my_square(n):
        return n*n
    #求阶乘
    def my_factorial(n):
        result=1
        for i in range(2,n+1):
            result *= i
        return result
    #调用局部函数
    if type=="my_square":
        return my_square(value)
    else:
        return my_factorial(value)

#调用全局函数
print(my_math_func("my_square",3))  #9
print(my_math_func("my_factorial",5))  #120

四、 函数之高级内容

python中函数本身也是一个对象,可作变量、可作其他函数参数、还可作其他函数返回值

1. 使用函数变量

可以将函数本身赋值给变量,被赋值后的变量相当于该函数

def my_square(n):
    return n*n

#注意这里不是调用函数,只是将函数赋值给变量
my_fun=my_square
#调用赋值后的变量
print(my_fun(5))  #25

2. 使用函数作为形参

某些程序代码可能需要动态改变,如果希望调用函数时能动态传入这些代码,便需要在函数中定义函数形参

def map(data,fun):
    result=[]
    #遍历data列表中每个元素,并用不同fn函数对data元素进行计算,计算结果存入result列表
    for i in data:
        result.append(fun(i))
    return result

#求平方
def my_square(n):
    return n*n
#求阶乘
def my_factorial(n):
    result=1
    for i in range(2,n+1):
        result *= i
    return result

#调用map函数,每次传入不同函数作为参数
data=[3,5,2,4,1]
print(map(data,my_square))  #[9, 25, 4, 16, 1]
print(map(data,my_factorial))  #[6, 120, 2, 24, 1]

3. 使用函数作为返回值

def my_math_func(type):
    #求平方
    def my_square(n):
        return n*n
    #求阶乘
    def my_factorial(n):
        result=1
        for i in range(2,n+1):
            result *= i
        return result
    #注意这里没有调用局部函数,只是将它们返回
    if type=="my_square":
        return my_square
    else:
        return my_factorial

#调用my_math_func,程序将返回一个嵌套函数
print(my_math_func("my_square"))
#<function my_math_func.<locals>.my_square at 0x000001BF39B29950>
print(type(my_math_func("my_factorial")))  #<class 'function'>

#将调用结果赋给变量,变量即会成为该局部函数
value_func=my_math_func("my_square")
print(value_func(10))  #100
value_func=my_math_func("my_factorial")
print(value_func(5))  #120

 

五、lambda表达式

可用于替代部分局部函数,简化写法。它更加灵活,可在程序中被传递和调用。

语法格式如下

lambda [par_list]:单行表达式
#例如  lambda x,y:x+y

优点:

  • 对于单行函数,可省去函数定义过程,使代码更简洁
  • 对不需多次复用的函数,lambda表达式可在用完后立即释放,提高性能

缺点:

  • 只支持单行表达式,只能替代一些非常简单的局部函数
def my_math_func(type):
    # 该函数返回lambda表达式
    result=1
    if type=="my_square":  #求平方
        return lambda n:n*n
    else:  #求立方
        return lambda n:n*n*n

#调用全局函数
#将调用结果赋给变量,变量即会成为该局部函数
value_func=my_math_func("my_square")
print(value_func(10))  #100
value_func=my_math_func("my_cube")
print(value_func(5))  #125

 

x=map(lambda x:x*x,range(8))
print([i for i in x])  #[0, 1, 4, 9, 16, 25, 36, 49]

#若x为偶数,求平方,否则设为0
y=map(lambda x:x*x if x%2==0 else 0,range(8))
print([i for i in y])  #[0, 0, 4, 0, 16, 0, 36, 0]