疯狂python讲义学习日志04——函数和lambda表达式

1 引言

面向过程和面向对象是python的两大编程核心机制,而函数和lambda表达式是面向过程实现的重要内容,这篇文章将详细说明python中函数和lambda表达式中的详细内容。

2 函数入门

2.1 定义函数和调用函数

  • python声明函数必须使用def关键字
def 函数名 ():
   	//由零条到多条的可执行语句组成的函数
   	[return [返回值]]
  • 函数名应该是一个或多个有意义的单词连缀而成,每个单词字母全部小写,单词之间用下划线分隔。
  • 形参列表用于定义函数可以接收的参数,可以由多个参数组成,参数之间通过逗号分隔开。
def   my_max(x,y):
   	#定义一个变量z,该变量等于x,y中的最大值
   	z= x if x>y else y
   	#返回变量z的值
   	return z

2.1 为函数提供文档

python可以为函数编写说明文档,只要把一段字符串放在函数声明之后、函数体之前,这段字符串将作为函数的一部分,这个文档就是说明文档。
程序可以通过help()函数查看函数的说明文档,也可以通过函数的_doc_属性访问函数说明文档。

def my_max(x,y):
   """
   获取两个数值之间的最大值
   my_max(x,y)
       返回x,y两个参数之间的较大数
   """
   z= x if x>y else y
   return  z
help(my_max)
print(my_max._doc_)

2.3 多个返回值

python函数可以直接返回多个值,python会自动将多个值封装为元组。

def sum_and_avg(list):
    sum=0
    count =0
    for e in list:
        if isinstance(e,int) or isinstance(e,float):
            count+=1
            sum+=e
    return sum,sum/count
my_list =[20,15,2.8,'a',35,5.9,-1.8]
tp = sum_and_avg(my_list)
print(tp)
s,avg = sum_and_avg(my_list)#序列解包
print("总和:",s,"平均值:",avg)

3 函数的参数(重点内容)

3.1 关键字参数

按照形参位置传入的参数被称为位置参数,如果根据参数参数名传入参数,则无须遵守定义形参的顺序,这种方式被称为关键字参数。

def grith(width,heght):
    print ("width",width)
    print("height",heght)
    return  2 * (width+heght)
#传统方式调用,根据位置参数传入
print(grith(3.5,4.8))
#根据关键字参数调用
print(grith(width=3.5,heght=4.8))
print((grith(heght=4.8,width=3.5)))
print(grith(3.5,heght=4.8))#如果混合使用则关键字参数在位置参数之后

3.2 参数默认值

python可以为一个或多个形参定义默认值,调用函数时就可以省略为形参传入参数值,而是直接使用该形参的默认值。

def say_hi(name="孙悟空",message="欢迎来到疯狂软件"):
    print(name,",您好")
    print("消息是:",message)
#全部使用默认参数
say_hi()
#只有message使用默认参数
say_hi("白骨精")
#两个参数都不使用默认参数
say_hi("白骨精","欢迎学习python")
#只有name参数使用默认值
say_hi(message="欢迎学习python")
  • 因为python要求调用函数时关键字参数必须在默认参数之后,因此在定义函数时指定了默认值的参数必须在没有指定默认值的参数之后。

3.3 参数收集(个数可变的参数)

python允许在形参前面添加一个*号,这样就意味着该参数可以接收多个参数值,多个参数值被当成元组传入。而且允许该参数出现在任何位置,但是一个参数最多只能支持一个带参数收集的形参。

def test(a,*books):
    print(books)
    #books被当成元组处理
    for b in books :
        print(b)
    #输出整数变量a的值
    print(a)
test(5,"疯狂ios讲义","疯狂andriod讲义")

python还可以支持收集关键字参数,python内部会将这种关键字参数收集成字典。定义时需要在该参数前面添加两个星号,一个函数可以同时包含一个支持普通参数收集的参数和一个支持关键字参数收集的参数。

def test(x,y,z=3,*books,**stores):
    print(x,y,z)
    print(books)
    print(stores)
test(1,2,3,"疯狂python讲义","疯狂android讲义",语文=89,数学=94)

3.4 逆向参数收集

逆向参数收集是指程序向函数传递列表、元组、字典等对象,函数将他们分开当成参数传入执行。逆向参数收集需要在传入的列表、元组等参数之前添加一个星号,在字典参数之前添加两个星号。

def test(name, message):
    print("用户是:",name)
    print("欢迎消息:",message)
my_list = ['孙悟空','欢迎来到疯狂软件']
test(*my_list)

即使函数支持收集的参数,如果程序需要将一个元组传给该参数也需要逆向收集。

def foo(name, *nums):
    print("name参数:",name)
    print("nums参数:",nums)
my_tuple=(1,2,3)
foo('fkit',*my_tuple)#如果不使用逆向收集,则该元组直接赋值给第一个参数

字典也可以支持逆向收集,字典将会以关键字的形式传入。

def bar(book, price,desc):
    print(book,"这本书的价格是:", price)
    print('描述信息',desc)
my_dict = {'price':89,'book':"疯狂python讲义", 'desc':'这是一本系统全面的python学习图书'}
#按逆向收集的方式进行调用
bar(**my_dict)

3.5 函数的参数传递机制

python中的参数传递机制都是"值传递的形式的",即将参数副本传入参数,参数本身不会收到任何影响。

def swap(a,b):
    #下面代码实现a,b变量的值交换
    a,b = b,a
    print("在swap函数里,a的值是",a ,"b的值是",b)
a=6
b=9
swap(a,b)
print("交换结束后,变量a的值是",a,"变量b的值是",b)

疯狂python讲义学习日志04——函数和lambda表达式_第1张图片
上图说明了在主程序中调用swap()函数时,系统分别为主程序和swap()函数创建了两块栈区,用于保存他们的局部变量。将主程序中的a、b变量作为参数传入swap()函数,实际是是在swap()函数栈区中重新产生了两个新的变量,并分别利用主程序的a、b变量初始化,swap函数只是完成了所在栈区变量的数值交换,充分说明了python函数调用值传递的特性。
如果函数参数是一个对象也是通过值传递的方式进行的。

def swap(dw):
    #下面代码实现dw两个元素的值交换
    dw['a'],dw['b']=dw['b'],dw['a']
    print("在swap()函数里,a元素的值是",dw['a'],"b元素的值是",dw['b'])
dw={'a':6,'b':9}
swap(dw)
print("交换结束后,a元素的值是",dw['a'],"b元素的值是",dw['b'])

疯狂python讲义学习日志04——函数和lambda表达式_第2张图片
由于dw是一个引用变量,所以传入函数之后还是一个引用。swap函数通过引用直接可以操做对象本身。
至此,可以总结两个结论:

  • 不管什么类型的对象,在python函数中对参数直接使用“=”赋值是没有用的,不能改变参数。
  • 如果需要修改哪些数据,则可以将数据封装为对象通过传递对象引用的方式修改参数数值。

3.6 变量作用域

python提供了三个工具函数来获取指定范围内的“变量字典”

  • locals()总是获取当前局部函数范围内所有变量组成的“变量字典”。而globals()无论在哪里执行都是获取全局范围内的所有变量组成的字典变量。
  • 一般来说,使用locals()和globals()获取的“字典变量”只应该被访问,不应该被修改。实际上获取的全局变量都可以被修改,获取的局部范围内的“变量字典”即使对他修改也不影响局部变量。
def test():
   age =20
   #直接访问age局部变量
   print(age)
   #访问局部范围内的变量数组
   print(locals())
   #通过局部变量范围内的"变量数组"访问age
   print(locals()['age'])
   #通过局部变量范围内的变量数组修改age
   locals()['age']=12
   #再次访问age
   print(age)
   #通过global函数修改全局变量x
   globals()['x']=19
test()
x=5
y=20
print(globals())
print(locals())

python规定在函数内部对不存在的变量赋值时,默认就是重新定义了新的局部变量。

  • 访问被遮蔽的局部变量(通过globals()函数实现)
name = 'charlie'
def test():
   #通过globals()函数访问name全局变量
   print(globals()['name'])
   name = '孙悟空'
test()
print(name)

4 局部函数

python支持在函数内部定义函数,称为局部函数。默认情况下布局函数是对外隐藏的,其封闭函数也可以返回局部函数,以便在其他作用域继续使用该局部函数。

def foo():
    #局部变量name
    name = 'charile'
    def bar():
        #访问name
        nonlocal  name
        print(name)
        name = '孙悟空'#遮蔽了name,可以通过nolocal访问所在函数内部的变量
    bar()
foo()

5 函数高级内容

5.1 使用函数变量

python的函数也是一种值:所有函数都是function对象,可以把函数本身赋给变量。

def pow(base, exponent):
    result = 1
    for i in range(1,exponent+1):
        result*=base
    return  result
my_fun = pow
print(my_fun(3,4))

5.2 使用函数作为函数形参

def map(data,fn):
    result =[]
    #遍历data列表中的每个元素,并用fn函数对每个元素进行计算
    #然后将计算结果作为新的数组元素
    for e in data:
        result.append(fn(e))
    return result
def squre(n):
    return  n*n
data = [3,4,9,5,8]
print(map(data,squre))

5.3 函数作为返回值

def get_math_func(type):
    def squre(n):
        return n*n
    if type == "squre"
        return squre
math_func = get_math_func("squre")

6 局部函数与lambda表达式

6.1 使用lambda表达式代替局部函数

def get_math_func(type):
    result =1
    #该函数返回的时lambda表达式
    if type == "squre":
        return lambda n : n * n
math_func=get_math_func("squre")
print(math_func(5))

lambda表达式使用要点:

  • 必须使用关键字定义
  • 关键字之后,冒号左边是参数列表,可以没有参数,也可以有多个参数。
    lambda表达式用途:4
  • 对于单行函数,可以省去函数定义过程使代码更加简洁 。
  • 对于不需要多次复用的函数,使用lambda表达式用完之后可以立即释放,提高了性能。

你可能感兴趣的:(Python学习日志)