免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

【Python3基础】07-函数基础与参数设计

【Python3基础】07-函数基础与参数设计 ▒ 目录 ▒ 导读本篇知识路线1️⃣ 函数定义和调用函数定义函数参数函数返回值2️⃣ 函数参数详解位置参数默认参数默认参数详解可变参数关键字参数命名关键字参数各种类型参数组合使用3️⃣ 参数设计的补充规则 文章小结 导读函数把一段程序从“能运行”提升为“能复用、能测试、能维护”。本篇从函数定义、调用和返回值开始系统梳理位置参数、默认参数、可变参数和关键字参数。参数设计本质上是在定义函数的使用契约调用者需要提供什么函数会返回什么哪些内容可以省略。本篇知识路线调用参数 ──► 参数绑定 ──► 函数体 ──► 返回值 │ ├─ 位置参数 ├─ 默认参数 ├─ *args └─ **kwargs1️⃣ 函数定义和调用Python 的函数在形式上分为三种一种是 Python 内置的函数 一种是第三方库的函数一种是我们自己定义的函数但无论哪种形式 函数定义方式都是一样的。函数定义后我们就可以通过函数名和参数来调用函数本节我们就来学习如何定义函数和使用函数。函数定义Python 内置了很多函数我们可以直接调用要调用一个函数 需要知道函数的名称和参数的个数比如求绝对值的函数函数名称为 abs参数个数只有一个。print(abs(-8))想了解 python 内置函数的定义我们可以直接从 python 的官方网站查看文档https://docs.python.org/2/library/functions.html, 我们也可以在交互式命令行通过 help(函数名称) 查看该函数的帮助信息。C:\Users\fengfeng000123pythonhelp(abs)Help on built-infunctionabsinmodule __builabs(...)abs(number)-number Return the absolute value of the argument.Python 解释器内不可能内置过多的函数但也有些比较实用的函数会经常用到有些好心的程序员写好的一些库 经过官方评审后加入了 Python 安装包内在我们安装 Python 的时候就会把它们放在一些目录下 调用的时候只需要 import 库名 就可以了当然也有一些程序员写的库没有加入到 Python 安装包内我们只需要把它们下载下来即可使用。importtime time.sleep(3)print(三秒后我才出来)在项目开发中我们需要自己定义函数来实现项目的需求在 Python 中我们定义一个函数要使用 def 语句依次写出函数名括号括号中的参数和冒号 然后在缩进块中编写函数体函数的返回值用 return 语句返回。defmyabs(data):returndataifdata0else-data# 暂不考虑用户如果输入非数字类型数据print(myabs(-9))在 python 中我们定义一个函数但是还没想好怎么写函数的代码可以用 pass 语句这种函数就是空函数pass 语句什么都不做实际上 pass 可以用来作为占位符。defmyfunc():pass函数参数调用函数时如果参数个数不对Python 解释器会自动检查出来并抛出 TypeError。defbeauty(age):ifage20:returnbeautyreturnauglybeauty()# 参数个数不对由于 Python 是弱类型语言如果调用者传入的参数类型不符合我们要求Python 解释器就无法帮我们检查 我们可以用 Python 内置的数据类型检查函数 isinstance 来从逻辑上检查参数类型是否匹配isinstance 函数可以判断某个对象是属于某种类型或者某些类型中的一种用 tuple是的话返回 True否则返回 False。defmyabs(data):ifisinstance(data,(int,float)):returndataifdata0else-datareturn参数类型不对print(myabs(hello))我们虽然可以用 isinstance 函数来检查数据类型但是我们想在用户给的参数不符合我们的要求时 最好抛出异常终止程序执行而不是给用户返回一个提醒。defmysquare(data):try:rstdata*dataexcept:raiseTypeError(类型错误请输入数字类型)returnrstprint(mysquare(hello))函数返回值其它语言一般只能返回一个值而 Python 和大多数其它语言不同可以返回多个返回值当 Python 返回多个值的时候python 解释器把这些值放进一个 tuple 里面所以 Python 的函数返回多值其实就是返回一个 tuple该 tuple 本质上也是一个值。defmyfunc():returnruhua,xingxing,zhaoritianrstmyfunc()print(rst)# 可以看到是一个 tupleprint(type(rst))# tuple 类型当 python 返回多个值的时候接收变量个数只能为一个或返回值的个数 因为一个变量接收的是整个 tuple而多个变量接收的是 tuple 里面成员的个数。defmyfunc():returnruhua,xingxing,zhaoritianrstmyfunc()# okone,two,threemyfunc()# okone,twomyfunc()# 错误函数体内部的语句在执行时一旦执行到 return 时函数就执行完毕并将结果返回 如果没有 return 语句函数执行完毕后也会返回结果只是结果为 None。defmyfunc():namemyfuncprint(myfunc())2️⃣ 函数参数详解定义函数的时候我们把参数的名字和位置确定下来函数的接口定义就完成了对于函数的调用者来说只需要知道如何传递正确的参数以及函数将返回什么样的值就够了函数内部的复杂逻辑被封装起来调用者无需了解。Python 的函数定义非常简单但灵活度却非常大除了正常定义的必选参数外还可以使用默认参数、可变参数和关键字参数使得函数定义出来的接口不但能处理复杂的参数还可以简化调用者的代码本节我们就来学习函数的各种参数定义。位置参数位置参数也叫必传参数也就是函数的实参的个数和位置必须和形参的个数和位置一致。说明我们把函数定义时的参数叫做形参调用函数时给的参数叫做实参。defmyfunc(name,age):print(name)print(age)myfunc(ruhua,18)# 实参 ruhua 对应形参 name实参 18 对应形参 agemyfunc(ruhua,zhaoritian,18)# 错误实参和形参的参数个数不匹配Python 是动态语言在定义函数的时候没法给形参定义类型所以我们需要对调用的函数参数类型说明要清楚不然会得到错误的逻辑结果。defmyfunc(name,age):print(name)print(age)myfunc(18,ruhua)# 实参 18 对应形参形参 name实参 ruhua 对应形参 age默认参数在函数定义时如果给某个参数提供一个默认值这个参数就变成了默认参数不再是位置参数了。在调用函数的时候我们可以给默认参数传递一个自定义的值也可以使用默认值。defgirlsschool(name,sexf):print(name)print(sex)girlsschool(wanghuahua)girlsschool(ruhua,m)有多个默认参数时调用的时候既可以按顺序提供默认参数也可以不按顺序提供部分默认参数当不按顺序提供部分默认参数时需要把参数名写上。defgirlsschool(name,age18,sexf):print(name)print(age)print(sex)girlsschool(ruhua,sexm,age17)使用默认参数时要确保位置参数在前默认参数在后否则 Python 的解释器会报错。其实大家可以思考一下原因如果默认参数在位置参数前面由于位置参数是按次序接收实参的所有默认参数在实参中必须给出这样的话默认参数就没法默认了。defgirlsschool(age18,name):# 函数参数定义错误passdef_girlsschool(name,age18):# okpass默认参数详解从一个例子说起对于以下代码我们预期的结果是调用func()L 的值是 [2]再次调用func()L 的值还是 [2]而结果是[2][2, 2]。deffunc(L[]):L.append(2)print(L)func()func()我们都知道函数的默认参数也是局部变量但 Python 的函数在第一次使用默认参数的时候该默认参数指向的内存就确定了这与其他语言不同在其他语言中默认参数每次调用都要重新分配内存我们打印出默认参数 L 的 id 发现两次调用都是一样。deffunc(L[]):print(id(L))L.append(2)print(L)func()func()我们通过在函数体内定义一个局部变量来看下 Python 解释器的行为我们发现两次调用 L 指向的内存确实不是一个第一次结果为 [2] 第二次结果为 [2]但是打印出的内存地址确是一样的。deffunc():L[]print(id(L))L.append(2)print(L)func()func()导致上面结果的原因是内存分配机制是一样的我们可以通过下面的代码来证明通过下面的代码我们发现第一次调用 func 函数中 L 的 id 和 mylist 的 id 是一样的和第二次调用 func 函数中 L 的 id 并不一样。deffunc():L[]print(id(L))L.append(2)print(L)func()mylist[]print(id(mylist))func()对于默认参数是变量的情况出现的坑我们可以通过修改默认参数的值为常量来避免。deffunc(LNone):ifnotisinstance(L,list):L[]L.append(2)print(L)func()func()为什么要设计 strNone 这样的不变对象呢因为不变对象一旦创建对象内部的数据就不能修改 这样就减少了由于修改数据导致的错误。此外由于对象不变多任务环境下同时读取对象不需要加锁 同时读一点问题都没有所以我们在编写程序时如果默认参数可以设计一个不变对象那就尽量设计成不变对象。可变参数在 Python 函数中实参个数可以是不固定的就是我们调用函数时传入的实参个数是可变的可以是任意个数还可以是 0 个可变参数的形参要写成 *变量名 的形式。deffunc(*arg):print(arg)func()func(1)func(1,2,3)对于定义可变参数的函数我们调用函数时无论传入的实参参数类型是什么个数是多少个包括 0 个 Python 解释器都会把对应的实参组成一个 tuple 传给形参。deffunc(*arg):print(arg)func()# 0 个实参arg 被组成 ()func(1,2)# 2 个实参arg 被组成 (1, 2)func(hello)# 1 个实参arg 被组成 (hello,)func(1,[1,2])# 2 个实参arg 被组成 (1, [1, 2])func((1,2))# 1 个实参arg 被组成 ((1, 2),)func({1:2})# 1 个实参arg 被组成 ({1: 2},)如果传入的实参类型是集合str, list, tuple, dict, set) Python 允许在实参前面加一个 * 号此时 Python 解释器则会把实参中的所有成员字典是键展开。deffunc(*arg):print(arg)# 解释器会把 *hello 展开为 h,e,l,l,o实参变为(h,e,l,l,o)func(*hello)# 解释器会把 *[1, 2] 展开为 1, 2实参变为(1, 1, 2)func(1,*[1,2])# 解释器会把 *(1, 2) 展开为 1, 2实参变为(1, 2)func(*(1,2))# 解释器会把 *{1: 1, 2: 2} 展开为 1, 2 实参变为(1, 2)func(*{1:1,2:2})如果可变参数在位置参数或默认参数的前面就变成了命名关键字参数下面学习。defgirlsschool(*sex,name):# 命名关键字参数下面讲解定义passdef_girlsschool(*sex,age18):# 命名关键字参数下面讲解定义passdef_girlsschool(*sex,age,nameruhua):# 命名关键字参数下面讲解定义passdef_girlsschool(*sex,age18,name):# 命名关键字参数下面讲解定义passdef_girlsschool(name,*sex,age18):# 命名关键字参数下面讲解定义passdef_girlsschool(nameruhua,*sex,age):# 命名关键字参数下面讲解定义pass关键字参数可变参数允许你传入 0 个或任意个参数我们知道这些可变参数在函数调用时自动组装为一个 tuple。而关键字参数允许你传入 0 个或任意个含参数名的参数这些关键字参数在函数内部自动组装为一个 dict。deffunc(**arg):print(arg)func()func(nameruhua,age18)如果传入的实参类型是 dictPython 允许在实参前面加一个**号此时 Python 解释器则会把字典类型的实参转为 keyvalue 的形式。deffunc(**arg):print(arg)stuents_dict{name:ruhua,age:18}# 解释器会把 **stuents_dict 转为 nameruhua, age18最后的实参为(nameruhua, age18)func(**stuents_dict)# 解释器会把 **stuents_dict 转为 nameruhua, age18最后的实参为(sexf, nameruhua, age18)func(sexf,**stuents_dict)要确保关键字参数在可变参数和默认参数和位置参数的后面否则 Python 的解释器会报错。defgirlsschool(name,age18,**beauty,*sex):# 函数参数定义错误passdef_girlsschool(name,age18,*sex,**beauty):# okpass命名关键字参数命名关键字参数是在 Python 3 中新增加的一种语法它和关键字参数**kw不同命名关键字参数需要一个特殊分隔符**后面的参数被视为命名关键字参数。例如只接收 sex 和 lover 作为关键字参数这种方式定义的函数如下。defHuman(name,age,*,sex,lover):print(name,age,sex,lover)Human(ruhua,18,sexf,lovertangbohu)如果函数定义中已经有了一个可变参数后面跟着的命名关键字参数就不再需要一个特殊分隔符*了。defHuman(name,age,*args,sex,lover):print(name,age,args,sex,lover)Human(ruhua,18,sexf,lovertangbohu)命名关键字参数必须传入参数名这和位置参数不同如果没有传入参数名Python 解释器则报异常。defHuman(name,age,*,sex,lover):print(name,age,sex,lover)Human(ruhua,18,f,tangbohu)# 必须要指定参数名 sex 和 lover命名关键字参数可以有默认值从而简化调用给命名关键字参数设置默认值和给默认参数设置默认值的规则不一样命名关键字参数不限制默认值的顺序。defHuman(name,age,*,sex,lovertangbohu):print(name,age,sex,lover)Human(ruhua,18,sexf)##################我是分割线##################defHuman(name,age,*,sexf,lover):print(name,age,sex,lover)Human(ruhua,18,lovertangbohu)各种类型参数组合使用在 Python 中定义函数可以用位置参数默认参数可变参数和关键字参数这 4 种参数都可以一起使用或者只用其中某些但是请大家养成一个好习惯尽量不要使用命名关键字参数参数定义的顺序最好按照必选参数默认参数可变参数和关键字参数的写法。deffunc(a,bok,*c,**d):pass参数组合混用的时候如果形参的默认参数后面有可变参数传给默认参数的实参最好不要指定名称。defgirlsschool(age18,*sex):print(age)print(sex)girlsschool(age19,f)# 错误3️⃣ 参数设计的补充规则默认参数适合稳定、不易变化的默认值。列表、字典等可变对象不宜直接作为默认值可以使用None作为占位再在函数体内创建对象。函数接口较复杂时可以用仅位置参数和仅关键字参数约束调用方式类型提示与文档字符串则可以让参数含义更容易被编辑器和读者理解。 文章小结函数用参数接收输入用return返回结果没有显式返回值时结果为None。调用前应明确可接受的数据类型。区分位置参数、关键字参数、默认参数、*args和**kwargs可变默认值会跨调用共享通常改用None后在函数内创建新对象。可实现绝对值函数并测试数字、布尔值、None等输入检查异常处理是否准确再用转发参数的小函数观察*args与**kwargs的用途。
返回列表