P42-P45 认识函数

1. 函数的定义

        函数是组织好的可以重复使用的代码段。函数可以提高应用的模块性和代码的重复使用率。

函数的参数(形式参数)可以支持多个。

def mufun1(name,times):
    for i in range(times):
        print(f'I love {name}')
mufun1('python',5)

2. 函数的返回值

        函数的返回值,打个比方,len()函数返回可迭代对象的长度,而自定义函数的返回值依靠return语句。

        return语句用于退出函数,选择性地向调用方返回一个表达式。不带参数值的return语句返回None。

def div(x,y):
    if y==0:
        return '除数不能为0'
    else:
        return x/y
print(div(10,0))
print(div(10,5))

def div1(x,y):
    z = x/y
    print(z)
div1(10,5)
print(div1(10,5))

 

        此处div1()函数没有定义返回值,其返回值默认为None,而print()函数打印函数时是先执行函数体内部的内容,然后打印函数的返回值,例如print(print())返回的值是None。

3. 函数的参数

        函数的参数可以分为形式参数和实际参数,简称形参实参。上面函数的定义中,myfun1()函数中括号定义的name,times就是形参,传入的 'python' 、5就是实参。

        实参默认按照形参定义的顺序进行传递,此时的实参称为位置参数,同时实参也可以指定函数形参的值,此时的实参称为关键字参数。位置参数必须在关键字参数之前。

① 关键字参数

def myfun2(s,v,t):
    return ''.join((t,v,s))
print(myfun2(t = '我', v = '爱', s = '你')) # -> 我爱你

print(myfun2('我','爱','你')) # -> 你爱我
print(myfun2('我','爱', t='你')) # -> 你爱我
print(myfun2('我','爱', v='你')) # -> 异常 got multiple values for argument 'v'
print(myfun2(s='我','爱','你')) # -> 报错 positional argument follows keyword argument 

        此处的join方法是 将序列中的元素以指定字符链接生成一个新的字符串。譬如将上面代码段中return后面的语句改为’-‘.join([t,v,s])则返回 "我-爱-你"。

 ②  默认参数

        默认参数实在函数定义形参时给形参赋予的默认值。如果默认参数没有被传入新的值,则保持不变。

        使用默认参数需要将其放到最后 不然会报错。

def myfunc3(s,v,t='我'):
    return ''.join((t,v,s))
print(myfunc3('香蕉','吃'))  # -> 我吃香蕉

def myfunc3(s='我',v,t):
    return ''.join((t,v,s))
print(myfunc3('香蕉','吃')) # -> 报错 non-default argument follows default argument

③ / 和 * 

/

 

        看一下内置函数sum 和 abs的帮助文档, 可以发现定义形参时有一个 / 符号,/ 之前的参数必须传入位置参数,/ 之后的可以是位置参数也可以是关键字参数,自定义函数也遵循这一规则。

print(sum([1,2,3],4)) # -> 10
print(sum([1,2,3],start=4)) # -> 10
print(abs(-1.5)) # -> 1.5
print(abs(x=-1.5)) # -> 报错

* 左侧的参数可以是位置参数和关键字参数 ,但是右侧只能是关键字参数

def abc(a,*,b,c):
    print(a,b,c)
abc(1,c=2,b=3)  # -> 1,3,2
abc(a=1,c=2,b=3) # -> 1, 3, 2
abc(1,2,3) # -> 异常 abc() takes 1 positional argument but 3 were given

④ 不定长参数(收集参数)

*args

        想传入多少实参就传入多少实参的形参 称为收集参数,例如print()函数可以print很多实参。定义收集参数,只需要在形参前加上 * 。

def myfun(*args):
    print('有{}个参数'.format(len(args)))
    print('第二个参数是{}'.format(args[1]))
    print(args)
    print(type(args))
myfun('python','java','c++')  

        可以看到,上述args的type类型是元组, *args(arguements)其背后的原理就是元组的打包和解包功能。

        不难想到,若*args后面还跟有形参,则传入实参时必须使用关键字参数。和上述 * 中的一样,def abc(a,*,b,c) 中*相当于一个匿名的收集参数。

**kwargs

        收集参数不光可以将参数打包为元组,还可以将参数打包为字典。 **kwargs(keyword-argumes)。此时传入的实参只能是关键字参数,类似于键值对。

def myfunc(**kwargs):
    print(kwargs)
myfunc(a=1,b=2,c=3)

def myfunc(a,*b,**c):
    print(a,b,c)
myfunc(1,2,3,4,x=5,y=6)

         *不光可以用在形参里打包实参,也可以用在实参里实现参数解包。

args = (1,2,3,4)
kwargs = {'a':1, 'b':2, 'c':3, 'd':4}
def myfunc(a,b,c,d):
    print(a,b,c,d)
myfunc(*args)
myfunc(**kwargs)

 4. 函数变量的作用域----LEGB规则

① 局部变量与全局变量

        如果变量被定义在函数的里面,则这个变量的作用域仅限于函数体内部,称为局部变量

def myfunc():
    x = 520
    print(x)
myfunc() # -> 520
print(x) # -> name 'x' is not defined

        如果在任何一个函数的外部去定义一个变量,改变量作用于全局,称为全局变量

x = 880
def myfunc():
    print(x)
myfunc() # -> 880
print(x) # -> 880

        在函数内部,局部变量会覆盖同名的全局变量,但是出了函数,局部变量就失效了。

x = 880
def myfunc():
    x = 520
    print(x)
myfunc() # -> 520
print(x) # -> 880

        但如果在函数内部采用global语句将局部变量声明为全局变量,就可以在函数体内部改变全局变量的值。

x = 880
def myfunc():
    global x
    x = 520
    print(x)
myfunc() # -> 520
print(x) # -> 520

② 嵌套函数及LEGB规则

        嵌套函数中嵌套进去的内部函数是不可以直接调用的。可以在定义外部函数时对内部函数就直接调用。对于嵌套函数的作用域,内部函数可以访问到外部函数的局部变量,但是无法修改它。只能通过nonlocal语句才可修改。

def funA():
    x = 520
    def funB():
        x = 880
        print('in funB, x = ',x)
    funB()
    print('in funA, x = ',x)
funA()

def funA():
    x = 520
    def funB():
        nonlocal x  # -> 采用nonlocal语句
        x = 880
        print('in funB, x = ',x)
    funB()
    print('in funA, x = ',x)
funA()

 

         可以看到,如此多的作用域,它们之间的影响范围又存在相互覆盖的情况,那么当冲突发生时,python会选择谁呢?这里不得不说明一下python的变量解析机制---LEGB规则

        L --- Local 局部作用域

        E --- Enclosed 嵌套函数外层作用域

        G ---Global 全局作用域

        B --- BIF(Build-In-Function) 内置函数

        这个规则什么意思呢。前面已经演示过,当局部变量和全局变量冲突时,python会使用局部变量(L 在 G 前),除非使用 global 语句;当嵌套发生时,局部作用域又会覆盖外层函数的作用域(L 在 E前),除非使用 nonlocal 语句,而对于嵌套函数 E-G 相当于普通函数的 L-G。

        最后,内置函数BIF最没有地位,起个变量名和它一样就可以覆盖它,因为 G 在 B 前,如:

str = 520
a = str(520)
print(str) # ->520
print(a) # -> 异常

注:本文内容总结于 《小甲鱼零基础入门学习python》视频课程P42-P45

原视频链接:【Python教程】《零基础入门学习Python》最新版_哔哩哔哩_bilibili

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

汪小涵不记谱、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值