Python之函数三千问(基础篇)

目录

函数定义格式:

函数的内存分析:函数也是对象

函数入口 :向函数传递参数

1.形参和实参:

2.可变参数和不可变参数:

3.位置参数:

4.默认值参数:

5.命名参数:

6.可变参数:

7.强制命名参数:

函数内部:对传入的参数进行逻辑处理。

全局变量和局部变量:

栈帧(stack frame):

函数出口:return语句

lambda表达式:

递归函数: 

嵌套函数:

nonlocal和global:

LEGB规则:

函数其它小用法:


函数是Python中重要的组成部分,它可以将代码封装起来,复用代码,可以很好的简化代码结构。

函数定义格式:

函数的内存分析:函数也是对象

内存分为栈内存和堆内存,函数在定义时,栈内存中存储的是函数的地址,用来找到堆内存中的函数对象,既然函数是对象,那么函数肯定具有函数类的相关属性和方法,比如函数使用的局部变量、返回值、内部__doc__方法等。

def test01():
    """
    我是测试函数
    """
    print("*"*10)

test01()
c = test01
c()

print(id(test01))
print(id(c))
print(type(test01))
print(type(c))
print(test01)
print(c)

函数入口 :向函数传递参数

函数参数有多种类型:实参、形参、可变参数、不可变参数、位置参数、默认参数、命名参数、可变参数、强制命名参数等。

1.形参和实参:

将函数外部拥有具体值的变量(有实际意义的参数)传入函数内部(函数括号中的参数叫做形参,形式上的参数)。

2.可变参数和不可变参数:

当传递形参时,形参按照类型分,又分为可变参数和不可变参数;因此向函数传递参数时,又要分可变参数和不可变参数。

可变参数,就是可以在原数据上改变的参数,比如(列表,字典)可以在已经定义的列表上进行增删改等操作。如果传入的实参是可变参数,实际上它传递的是实参对象的引用,在函数体中不创建新的对象拷贝,形参直接指向实参对象的引用,对外部实参进行修改。

不可变参数,只要是定义好的数据,就不可以在原数据上进行修改,比如(int,float,字符串,元组,布尔值)不可以在原数据上进行增删改等操作。如果传入的实参是不可变参数,实际上它传递的也是实参对象的引用,由于不可变的特性,会在函数体中创建新的对象,此时不会指向外部的实参对象,也就不会对外部实参进行修改。

传递可变参数:

b = [10,20]
def f2(m):
    print("m",id(m)) # b和m是同一个对象,id相同
    m.append(30) # 由于m是可变对象,不创建对象拷贝,直接修改这个对象

f2(b)
print("b:",id(b))
print(b) # 在函数内部改变了b,因此b=[10,20,30]

 传递不可变参数:

a = 100
def f1(n):
    print("n:",id(n)) # 传递a的地址
    n = n+200 # 由于a是不可变对象,因此创建新的对象n
    print("n:",id(n)) # n已经变成了新的对象,和a的id不同
    print(n)
f1(a)
print("a:",id(a))

传递可变参数内存分析:

 传递不可变参数内存分析:

传递可变参数和不可变参数其实涉及到深拷贝和浅拷贝知识点,其它博客有总结过相关知识点。

3.位置参数:

函数调用时,实参默认按位置顺序传递,需要个数和形参匹配,就是形参有几个就要传递几个实参,当然有默认参数的除外。

4.默认值参数:

为某些形参设置默认值,这样的参数在传递时是可选的。

5.命名参数:

如果不想像位置参数那样按照指定位置赋值,可以使用函数形参名称赋值,不用考虑顺序。

6.可变参数:

可变参数,可以理解为只有一个形参却可以接收任意数量的形参,将接收实参存储在元组或字典中。

1.*args(一个星号):将多个参数收集到一个“元组”对象中。

2.**kwgs(两个星号):将多个参数收集到一个“字典”对象中。

def f1(a,b,*c):
    print(a,b,c)

f1(1,2,3,4,6,7)

def f2(a,b,**c):
    print(a,b,c)

f2(8,9,name="cwj",age=18)

def f3(a,b,*c,**d):
    print(a,b,c,d)

f3(8,9,10,11,12,name="lzy",age=18)

7.强制命名参数:

指定形参名赋值,在带星号的“可变参数”后面增加新的参数,必须在调用的时候强制“命名参数”。

def f1(*a,b,c):
    print(a,b,c)
# f1(2,3,4)  # 会报错。由于a是可变参数,将2,3,4全部收集,造成b和c无数据
f1(2,b=3,c=4)

函数内部:对传入的参数进行逻辑处理。

当函数内部使用变量时,分为使用函数内部的变量还是函数外部的变量,内部的叫做局部变量,外部的叫做全局变量。

全局变量和局部变量:

全局变量和局部变量的主要区别在于变量的作用域不同,全局变量是在整个程序中,每个地方都可以访问到的变量,局部变量是只有在定义该变量的函数内部才可以访问的变量。

a = 100 # 全局变量

def test01(): 
    a = 300 #局部变量
    print("我是局部变量a={0}".format(a)) # a = 300

def test02():
    global a # 如果想要访问全局变量a,需要使用global
    print("我是全局变量a={0}".format(a)) # a = 100

def test03():
    global a # 设置全局变量,先global,再赋值
    a = 400
    print("我是全局变量a={0}".format(a)) # a = 400

test01() # 局部变量和全局变量重名,优先考虑局部变量
print(a) # 查看a是否被改变了

test02() # 访问全局变量
print(a) # 查看a是否被改变了

栈帧(stack frame):

简单理解就是函数局部变量创建时,生成栈帧用来存放局部变量,函数访问完毕,栈帧销毁,再次调用函数,再次创建栈帧。

函数出口:return语句

lambda表达式:

lambda表达式可以用来声明匿名函数,它是一种简单的定义函数的方式,只允许包含一个表达式,不能包含复杂语句。

lambda表达式的计算结果就是函数的返回值。

lambda表达式实际生成的是一个函数对象。

lambda表达式的基本语法如下:

f = lambda a,b,c:a+b+c
print(f)
print(f(2,3,4)) # 9

g = [lambda a:a*2,lambda b:b*3, lambda c:c*4]
print(g[0](2),g[1](3),g[2](4)) # 4 9 16

递归函数: 

递归函数简单的讲就是函数自己调用自己。在写递归函数的时候,一定要注意函数的终止条件,否则会造成栈溢出。

每个递归函数必须包括的部分:

1、终止条件:递归什么时候结束,一般使用return 返回。

2、递归步骤:把第n步和第n-1步相关联。

递归的缺点:由于递归函数会创建大量的函数对象,过量的消耗内存和运算能力,不适合处理涉及到很多数据的问题。

def fib(n):
    if n==1: # 1.终止条件
        return 1
    else:
        return n*fib(n-1) # 2.n和n-1相关联

print("5的阶乘:",fib(5))

嵌套函数:

在函数内部定义的函数,叫做嵌套函数。

def outer():
    print("outer running")
    
    def inner():
        print("inner running")

    inner()

outer()

nonlocal和global:

在使用嵌套函数的时候,如果内部函数想要使用外部函数的变量,需要借助关键字nonlocal来声明外部变量。

def outer():
    b = 10
    
    def inner():
        nonlocal b # 声明外部变量b
        print("inner b:",b) # 如果直接读取b的值,不需要使用nonlocal
        b = 20 # 如果没有使用nonlocal声明, 会报错UnboundLocalError
        
    inner()
    print("outer b:",b)

outer()

 在使用嵌套函数的时候,如果内部函数想要使用全局变量,需要借助关键字global来声明全局变量。

a = 888
def outer():
    b = 10
    global a 
    a = 999
    print("outer--->a",a)
    def inner():
        nonlocal b
        print("inner b:",b) # 如果直接读取b的值,不需要使用nonlocal
        b = 20 # 如果没有使用nonlocal声明, 会报错UnboundLocalError
        global a
        a = 666
        print("inner--->a:",a)
        
    inner()
    print("outer b:",b)

print("a:",a)
outer()
print("a:",a)

 

LEGB规则:

LEGB:函数查找同名变量的顺序,L --> E --> G --> B

str = "level 3" # 如果注释掉,会打印 <class 'str'> (Global) --> Bulid in
def outer():
    str = "level 2" # 如果注释掉,会打印 level 3 (Enclosed) --> (Global)
    def inner():
        str = "level 1" # 如果注释掉,会打印 level 2 (Local) --> (Enclosed)
        print(str)

    inner()

outer()

函数其它小用法:

函数.doc:获取函数多行字符串中的描述信息。

def test01():
    """
    我是测试函数
    """
    print("*"*10)

print(test01.__doc__)

会输出:我是测试函数

获取函数内部的局部变量和使用到的外部全局变量的方法:locals()和globals()

a = 100

def f1(a,b,c):
    print(a,b,c)
    print(locals()) # 打印输出局部变量
    print(globals()) # 打印输出全局变量

f1(2,3,4)

 

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值