P42-P45 认识函数

news/2024/11/19 18:45:00/

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/yprint(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 = 520print(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 = 520print(x)
myfunc() # -> 520
print(x) # -> 880

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

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

② 嵌套函数及LEGB规则

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

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

def funA():x = 520def funB():nonlocal x  # -> 采用nonlocal语句x = 880print('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


http://www.ppmy.cn/news/127789.html

相关文章

谷粒商城-基础篇-商品服务1-三级分类(P45-P58)

谷粒商城-基础篇2 一、商品服务-API-三级分类1、三级分类2、查出所有分类以及子分类2、配置网关路由与路径重写3、网关统一配置跨域4、查询-树形展示三级分类数据5、删除6、新增7、修改8、修改拖拽效果9、批量删除 商品服务-三级分类 一、商品服务-API-三级分类 1、三级分类 …

CSS基础(P45-P65)

一、基础认知 1.1CSS介绍 CSS:层叠式样表(Cascading style sheets),用来给页面中的HTML标签设置样式 常见属性:color颜色、font-size字体大小、background-color背景颜色、width宽度、height高度 注意点&#xff1…

Day07 狂神说Java-MySQL>P40-P45

P40 Statement对象详解 executeUpdate和executeQuery 提取工具类 package com.hu.lesson02.utils;import java.io.IOException; import java.io.InputStream; import java.sql.*; import java.util.Properties;public class JdbcUtils {private static String driver null;…

寨板p45黑苹果10.12.6

这不是一个教程哈,只是只是一些记录吧。教程的话后续会写哈,有兴趣的朋友可以关注一下。前段时间喜欢上折腾黑苹果了,花费一些时间确实成功给几台电脑装上了黑苹果,其中最老的就是这台台式机了,机子配置没有鲁大师截图…

谷粒商城P45-P58

文章目录 分布式基础篇csdn机制问题导致图片丢失,可以查看本人的个人博客:[谷粒商城-P45-P58](https://www.r2coding.vip/articles/2022/05/04/1651673906725.html)1. 三级分类1.1 sql脚本1.2 查出所有分类以及子分类1.2.1 后段代码编写1.2.2前端代码编写1.2.2.1配置网关路由…

x38和x48是服务器芯片吗,P45和P35区别是什么?

你不组CF的话,超频方面没什么太大区别,x38和x48的区别是x38支持ddr31600和fsb1600,p35和p45的区别是p45支持pcie 2.0.其实,p35完全够用,不建议你升级成p45或者x48之类的,当然,你要组cf的话列外。。。 2007年,在支持FSB 1333MHz的英特尔X38主板还没有正式上市之际,一些主板大厂…

P45:字符串变量、equals

** P45(字符串变量、equals): ** P45(字符串变量、equals): 一、什么是字符串?二、表达字符串的类型三、字符串变量的定义三、初始化字符串变量四、字符串的连接五、字符串的输出语法六、字符…

Intel P45芯片组介绍

一、芯片规格: 二、规格提升 1、全面普及PCIE2.0规范 NVIDIA和AMD新一代DX10高端显卡的都不约而同地采用了新工艺、加入了高清硬件解码引擎,而且,都能够支持新一代总线接口——PCI-Express 2.0。PCI Express 2.0规范的主要在数据传输速度上做…