从前面的几篇博客中,我们已经熟悉了print()、input()和len()函数。Python提供了这样一些内建函数,但你也可以编写自己的函数。"函数"就像一个程序内的小程序一样。

在之前的学习中,只是用Python实现了一些简单的功能,这些功能也只是由简单的流程控制语句配合数据类型(如列表、字典)实现,但是这些程序有着无法避免的缺陷,比如说:

  • 代码耦合性太高,各功能都糅合在一起,“干湿”不分离。
  • 扩展性差,由于代码都揉在一起,如果要添加新的功能,可能就要费一番功夫了。
  • 代码冗余,比如实现一个加法功能,那么当别处还需要这个功能的话,还要重新实现这个功能,这种情况多了,就是在重复的造轮子,这种情况是不可取的。
  • 可读性差,经过如上的几种不可避免操作之后,代码可读性就变得非常差。

列举了如上的几种目前代码的弊端之后,该如何解决呢?解决方法就是使用函数。其实我们在之前的学习中已经体会到函数的好处了,比如要计算一个列表的长度,可能想到用for循环解决问题:

count = 0
li = ['曹操','吕布','周瑜','孙权','马超','郭嘉']
for i in li:count += 1print(count)
# 结果为:
6

当要计算一串字符串、元组的长度,此时不可避免的陷入重复造轮子的过程。知道学习了len()函数之后。

li = ['曹操','吕布','周瑜','孙权','马超','郭嘉']
print(len(li))
# 结果为:
6

函数的定义与调用

创建(定义)函数

def <function_name>([arg1,arg2,...argn]):'''functional annotation'''passreturn

通过def关键字来定义函数,空格之后的function_name 为函数名(必须有),函数的命名规则参考变量的命名。括号(必须有)内的参数是可选的,括号后面的 : 也是必须的。注释部分为可选的(但强烈建议有注释,就像功能说明书一样),pass部分为函数的具体功能实现代码。执行结果视情况可以选择用return返回,如果没有显式的return具体内容的话,默认返货None。

虽然def 为关键字,但def也是可执行的语句,就是说当定义完函数之前,这个函数此时是不存在的:

print(dir())
def fun():pass
print(dir)
# 结果为:
['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__']
<built-in function dir>

第一个打印结果显示,当程序执行到def语句之前,fun函数不存在,而当def执行完毕,第二个打印结果告诉我们,当前的名称空间内存在了fun函数。

注意:dir()函数返回绑定在当前名称空间内(如果参数为空)的变量。

函数声明:

def 函数名(形式参数1):函数体return 函数结束语句

函数调用:

返回值变量 = 函数名(实际参数1)
返回值变量2 = 函数名(实际参数2)

当Python解释器执行到def 语句时,def语句创建一个函数对象并将这个对象赋值给def 后面的function_name变量。然后这个变量指向这个函数,或者说这个函数名(变量名)成为了这个函数的引用。因为def为执行语句,函数可以嵌套在if等语句内:

def fun():print("fun function")
def bar():print("bar 函数")
if 1:fun()
else:bar()for i in range(10):if i == 2:fun()else:bar()
# 结果为:
fun function
bar 函数
bar 函数
fun function
bar 函数
bar 函数
bar 函数
bar 函数
bar 函数
bar 函数
bar 函数

通过上面的栗子,也可以看到,fun() 和 bar()函数一处定义,多出调用。函数的特点:

  • 最大化的减少代码冗余和代码重用。
  • 程序的结构分解,也就是解耦合。
  • 打包打代码,使功能更加独立。

通过若干函数将整个程序的功能拆分开,每个功能都是独立的存在。而上述示例也说明了函数要先定义,后调用。(类似C++的变量,先声明,后使用)。而栗子中的函数加括号,是执行这个函数:

def fun():return 1print(fun)
# 输出结果为:
<function fun at 0x0000028C5CB261F0>
print(fun())
# 输出结果为:
1

由上示例可以看出,打印这个函数时,打印的时函数在内存中的地址,而打印这个函数加括号,打印的时这个函数的执行结果。

当定义了一个函数对象之后,这个对象允许任何附属功能绑定到这个函数对象上:

def fun():return 1def bar():pass
bar.a = fun()
bar.b = 3
print(bar.a)
# 输出结果为:
1
print(bar.b)
# 输出结果为:
3

可以看到,我们分别将fun函数的执行结果和整数3绑定到了bar函数对象上。

注意:养成良好的编程习惯,写注释。

虽然函数的注释是可选的,但我们强烈建议有注释(虽然后买你的栗子中为了节省空间且函数功能太小,有些可能不带),因为注释就相当与这个函数的说明书。

函数的返回值

  • 函数体中 return 语句有指定返回值时返回的就是其值
  • 函数体中没有 return 语句时,函数运行结束会隐含返回一个 None 作为返回值,类型是 NoneType,与 return 、return None 等效,都是返回 None。
def fun():passf = fun()
print(f)
# 结果为:
None

如上示例,如果函数没有显示的写return,那么默认返回None。我们可以理解为当我们没有写return时,该函数默认return None。

返回一个值

def fun():# return 1# return  'abc'# return  [1, 2, 3]# return {'name':'悟空'}return len('1234')f = fun()
print(f)
# 结果为:
4

可以看到return 返回的值是任意类型。

返回多个值

当一个函数返回多个值的时候,值之间需要用逗号隔开,最后多个值以元组的方式返回。

def fun():return 1, 2, {'name':'孙悟空'}, ['黑豹警长','舒克贝塔']print(ret)    # 这句没有打印result = fun()
print(result)
# 结果为:
(1, 2, {'name': '孙悟空'}, ['黑豹警长', '舒克贝塔'])
print(result[2])
# 结果为:
{'name': '孙悟空'}

由上例还可以发现,return 之后的print语句并没有执行。这也是return返回的另一个特点,那就是终止函数的执行。

函数的参数

之前示例中的函数并没有传递参数,这样的函数成为无参函数。对应的就是有参函数。有参函数的参数传参方式一般分为:位置参数、关键字传参、接收可变长度的参数、命名关键字参数。而在传递参数的时候,一般根据参数的实际意义来划分,函数接收的参数为形式参数(形参),调用函数的参数为实际参数(实参)。

def fun(x,y):       # x,y为:形式参数(形参)。print(x+y)return '计算完成!'
fun(5, 6)           # 5和6 为:实际参数(实参)
# 结果为:
11
f = fun(5, 6)
# 结果为:
11
print(f)            # return 返回"计算完成!"
# 返回值为:
"计算完成!"

函数的形参可以接受任意类型的参数,但又由于不确定接收的到底什么类型,所以称为形式参数。而调用时传递的参数就是一个具体的数据,所以称为实际参数。

通俗的说,形参就像萝卜坑,而实参就是萝卜,但萝卜也不能随便找个坑就好了,什么样的萝卜对应什么样的坑那是有规矩的。

常见的函数传参方式

常规参数,按位置匹配传参

def func(value):print(value)func("中国")
# 结果为:
中国

func函数,参数的传递按照位置传参。位置传参需要按照从左到右的顺序依次定义参数。

按位置传参的形参,必须被船只,而对应得实参,必须与形参一一对应,多一个不行,少一个也不行,位置不对,输出结果也不正确。

按照关键字传参,通过变量名匹配传参

def math1(a,b):print(a+b)math1(b=9,a=1)
# 结果输出为:
10

math1函数,按照关键字传参。关键字参数可以不用想位置实参一样与形参一一对应,而是指定参数的传值。多个关键字传参的话,因为指定将key传给指定的value,所以也就不必在乎前后顺序了,为了增强可读性,我们仍建议按照位置传参的形式为关键字传参。而当形参位置已经有值得话,则为默认参数,而默认参数在定义函数阶段,就已经为形参赋值,定义阶段有值,调用阶段如无必须无需船只。如果实参是经常变化得值,那么在定义位置是定义为位置形参,如果实参是不经常变化得时候,形参可以定义为默认参数。当位置参数和关键字参数都存在的话,位置参数优先级大于关键字参数。

def stu(value1,value2,value3):print(f'值1:{value1}, 值2:{value2}, 值3:{value3}')stu(99,value2=108,value3=2020)
# 结果为:
值1:99, 值2:108, 值3:2020def stu(name,gander="女"):print("姓名:{},性别:{}".format(name,gander))stu("黑猫警长","男")
# 结果为:
姓名:黑猫警长,性别:男
stu("小龙女")
# 结果为:
姓名:小龙女,性别:女

stu函数,以*args传递所有的实参对象,并作为一个(都被手机到元组内)基于位置的参数。就是说*args接受所有的出key=value格式的位置参数。

位置传参和可变长度搭配传参

def func5(value, *args):print(value, args)func5(1, 2, 3, 4, 5)  # 第一个参数按照位置传参,剩余的被 *args 收集
# 结果:
1 (2, 3, 4, 5)

func5函数,位置和可变长度的*args结合,从结果来看,从左到右的第一个参数按位置传递给了value,而剩余的位置参数都被*args接收。

*args接收任意长度的位置参数,并收集到元组中, 命名关键字参数value接收关键字参数

def func6(*args, value):print(args,value)func6("葫芦娃", "黑猫警长", "舒克贝塔", "齐天大圣", value=5)
# 命名关键字传参,前面被*args接收,value以key=value的形式传递
# 结果为:
('葫芦娃', '黑猫警长', '舒克贝塔', '齐天大圣') 5

func6函数,可变长度参数配合命名关键字参数(value),*args 接收所有位置参数,而当value在*args后面的时候,我们称其为命名关键字参数,而命名关键字参数定义在*后的形参,这类形参,必须被传值,而且要求实参必须是以关键字的形式来传值。

接受任意长度的key=value形式的参数,并收集到一个字典内,一般在所有的参数的后面。

def func7(**kwargs):print(kwargs)  # {'a': 1, 'b': 2, 'c': 3}func7(西游记='齐天大圣', 圣斗士='星矢', 四驱兄弟='小豪')
# 结果为:
{'西游记': '齐天大圣', '圣斗士': '星矢', '四驱兄弟': '小豪'}

func7函数,**kwargs接收任意长度的key=value合适的参数,并收集到字典中。注意:**kwargs还是要放到*args的后面。

各种传参混用,但是不推荐这种传参方式,提高了代码的复杂度,这里只是介绍可以这么用而已。

def func8(*args, **kwargs):print(args, kwargs)func8('猪八戒', '孙悟空', 3, 4, a=5, b=6)
# 结果为:
('猪八戒', '孙悟空', 3, 4) {'a': 5, 'b': 6}

func8函数,*args**kwargs一起使用的话,可以接收任意形式、任意长度的参数。但切记**kwargs还是要放到*args的后面。

Python基础 day08--函数基本使用相关推荐

  1. python的用途实例-Python基础之函数原理与应用实例详解

    本文实例讲述了Python基础之函数原理与应用.分享给大家供大家参考,具体如下: 目标 函数的快速体验 函数的基本使用 函数的参数 函数的返回值 函数的嵌套调用 在模块中定义函数 01. 函数的快速体 ...

  2. Python基础day08 作业解析【7道 面向对象题目】

    视频.源码.课件.软件.笔记:超全面Python基础入门教程[十天课程]博客笔记汇总表[黑马程序员] Python基础day08[面向对象(类.对象.属性).魔方方法(init.str.del.rep ...

  3. Python基础之函数

    详情请戳 python基础之函数介绍及使用 python基础之内置函数 python基础之迭代器和生成器 python基础之装饰器 转载于:https://www.cnblogs.com/zhangl ...

  4. Python数据结构与算法(1.5)——Python基础之函数与异常

    Python数据结构与算法(1.5)--Python基础之函数与异常 0. 学习目标 1. 函数 1.1 自定义函数 1.2 函数与参数 1.3 函数与返回值 2. 异常处理 2.1 raise 语句 ...

  5. 刻意练习:Python基础 -- Task05. 函数与Lambda表达式

    背景 我们准备利用17天时间,将 "Python基础的刻意练习" 分为如下任务: Task01:变量.运算符与数据类型(1day) Task02:条件与循环(1day) Task0 ...

  6. Python基础day08【面向对象(类、对象、属性)、魔方方法(init、str、del、repr)】

    视频.源码.课件.软件.笔记:超全面Python基础入门教程[十天课程]博客笔记汇总表[黑马程序员]   目录 0.复习 1.类外部添加和获取对象属性 2.类内部操作属性 3.魔法方法 3.1.__i ...

  7. Python基础__函数

    本节将进入函数的介绍,函数是Python基础中最精彩的部分之一,接下来将对函数做详细介绍. 函数 函数就是对代码进行一个封装.把实现某一功能的代码进行封装到一起.下次需要使用时不需要进行编写代码直接调 ...

  8. 『Python基础』函数

    Python中的函数 函数 (1)什么是函数? 软件开发,是为了解决生活中的问题,函数就是生活中的一种行为,如:吃饭.睡觉.学习.游戏等等等- 不需要资源.不需要结果.执行即可 关门的行为 需要资源. ...

  9. 第七篇 python基础之函数,递归,内置函数

    阅读目录 一 数学定义的函数与python中的函数 二 为何使用函数 背景提要 三 函数和过程 四 函数参数 五 局部变量和全局变量 六 前向引用之'函数即变量' 七 嵌套函数和作用域 八 递归调用 ...

  10. python入门之函数调用内置函数_第九篇 python基础之函数,递归,内置函数

    阅读目录 一 数学定义的函数与python中的函数 二 为何使用函数 背景提要 三 函数和过程 四 函数参数 五 局部变量和全局变量 六 前向引用之'函数即变量' 七 嵌套函数和作用域 八 递归调用 ...

最新文章

  1. Oracle 12c 新特性之 temp undo
  2. Linux下Minigui开发环境的搭建(PC+S3C2440
  3. java 8 并行_Java 8新特性之 并行和并行数组(八恶人-8)
  4. php v9开发网站,phpcms开发步骤
  5. 二位四进制计数器_金三银四还在看JVM这一块?看完这篇万字JVM面试解析就够了...
  6. 上层应用开发是否真的没有底层开发有前途?
  7. P1313 计算系数
  8. python 正则表达式 \b 大坑
  9. Java架构师成长之道之计算机组成原理概述篇
  10. 史上最难的初等几何问题?分享一个参考答案
  11. java尚硅谷 java基础第一个项目,记账软件
  12. centos php 开启libgdgd_linux gd
  13. 激光SLAM 前端数据预处理--剔除坏点方法总结
  14. portraiture4图片修图磨皮滤镜插件支持Win和Mac
  15. Xshell下载安装教程和使用教程(超详细)
  16. xml文件基本格式与解析
  17. github.io使用方法
  18. 国脉科技股份有限公司
  19. Linux配置yum源出现的问题
  20. 计算机硬件初中,初中信息技术-认识计算机硬件

热门文章

  1. Excel如何下拉实现按16进制递增?
  2. 应收账款和应付账款字段无效
  3. mac下Homebrew安装Fetching /usr/local/Homebrew/Library/Taps/homebrew/homebrew-cask failed报错解决方法
  4. fairygui富文本html语法怎么用,文本-FairyGUI 教程-面试哥
  5. ARM汇编指令xmind
  6. 质检总局:智能摄像头抽检八成存隐患,或致视频泄露
  7. 《Go程序设计语言》中文版翻译错误
  8. 『C/C++养成计划』C++项目遇到Aborted (core dumped)的处理方法
  9. 软件质量保证测试——共享车位
  10. 米莱狄机器人怎么那么多_王者米莱狄小机器人怎么变大机器人