之前的文章我们简单介绍了一下 Python 的几种变量类型,本篇文章我们来看一下 Python 中的函数。

函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。

函数能提高应用的模块性,和代码的重复利用率。你已经知道Python提供了许多内建函数,比如print()。但你也可以自己创建函数,这被叫做用户自定义函数。

你可以定义一个由自己想要功能的函数,以下是简单的规则:

  • 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号 ()
  • 任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。
  • 函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
  • 函数内容以冒号起始,并且缩进。
  • return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回 None。

Python 定义函数使用 def 关键字,一般格式如下:

 def 函数名(参数列表):
函数体
 def getNum():
pass

如果我们定义了一个函数,里面什么也没有写,为了不让代码崩溃,我们可以写一个 pass。

现在我们来定义一个可执行的函数:

 def getNum():
print(123)
getNum() #

如上我们定义了一个 getNum 的函数,函数内部 print 输出 123,当我们调用 getNum() 时,就会输出 123。

如果我们不想输出固定的 123,输出结果有我们自己定义,我们可以通过传参的形式解决:

def getNum(num):
print(num)
print(num * 2)
getNum(123) # 123 246

可以通过 return 的方式把想要的结果 return 出来:

 def getNum(num):
return num
print(getNum(123)) #

函数中也可以使用嵌套函数的方式:

 def getNum(num):
getName(num) def getName(name):
print(name) getNum("zhangsan") # zhangsan

我们通过向函数传值来获取我们的结果,也可以通过设置变量的形式来解决:

num = 1
def getNum():
print(num) getNum() #

上面的代码我们设置了一个全局变量,当然我们也可以在函数内部设置变量,叫做局部变量,这样更有利于我们对自己函数内的变量操作而不去改变全局的变量,如下:

 def getNum():
name = "zhangsan"
print(name) getNum() # zhangsan

在有的时候,我们可以直接将函数内的参数设置默认值,这就就可以避免在没有传入该参数时函数报错:

 def getNum(a, b, c=11, d=22):
print(a)
print(b)
print(c)
print(d) getNum(1, 2, 3) # 1 2 3 22

在上面的代码中,我们对函数 getNum 的第三个和第四个参数设置了默认值,在调用该函数时,我们传入了三个值,然后输出结果发现,第三个参数的默认值被调用 getNum 时传入的参数值覆盖掉了,而第四个参数值由于没有传入,所以使用了默认值 d=22。由此我们可以得出,当我们不传入对应参数值时如果设置默认值则使用默认值,如果传入了参数值则优先使用传入的参数值。

在上面的代码中,我们定义的参数都是单一的字符串或者数字,我们也可以定义列表,元组,字典这样的参数,如下:

 list = [11, 22, 33]
tuple = (44, 55, 66)
dict = {"a": "", "b": 88, "c": 99} def getTest(list, tuple, dict):
print(list)
print(tuple)
print(dict) getTest(list, tuple, dict)
'''
[11, 22, 33]
(44, 55, 66)
{'a': '77', 'b': 88, 'c': 99}
'''

在上面的代码中我们可以看出,Python 中的不同变量类型都可以作为参数传入函数中。

接下来我们再来看一下函数中缺省参数的 *args 和 **kwargs

 def getTest(a, b, c=123, *args):
print(a) #
print(b) #
print(c) #
print(args) # (44, 55, 66) getTest(11, 22, 33, 44, 55, 66)

在上面的代码中,print(c) 结果为 33,这个我们再上面已经解释过了,但是我们在参数 c 后面又加入了一个 *args 的形参,然后我们在调用 getTest() 时向函数内部传入参数的个数为 6 个,而函数体 getTest() 接收的参数为 4 个,按我们上面叫的函数方法,理论上程序应该报错,然而程序却能运行,运行结果打印的第 4 个参数结果为一个元组,将形参按顺序对应的参数对应完毕之后剩余的内容组成一个元组输出。其中 *args 可以写成 *xxx,我们习惯上命名为 *args。

在函数传参时,除了 *args 外还有一个 **kwargs,如下:

 def getTest(a, b, c=123, *args, **kwargs):
print(a) #
print(b) #
print(c) #
print(args) # (44, 55, 66)
print(kwargs) # {'name': 'zhangsan', 'age': 30} getTest(11, 22, 33, 44, 55, 66, name="zhangsan", age=30)

上面的代码中,我们在函数 getTest() 后面又多家了一个形参 **kwargs,当我们在调用 getTest() 函数并传入参数时,我们传入了 name="zhangsan" 这样的键值对,这样在打印输出 **kwargs 时会转为一个字典类型的数据。其中 **kwargs 可以写成 **xxx,我们习惯上命名为 **kwargs。

注意:在print() 输出时,*args 和 **kwargs 的 * 不需要写。

根据上面的 *args 和 **kwargs,我们现在来向这样一个问题,加入我先在外面分别定义了一个元组类型变量 tuple 和字典类型数据 dict,然后调用 getTest() 函数时将变量传入,输出结果还是跟上面的结果一样,即下面的代码:

 def getTest(a, b, c=123, *args, **kwargs):
print(a) #
print(b) #
print(c) #
print(args) # ((44, 55, 66), {'name': 'zhangsan', 'age': 30})
print(kwargs) # {} tuple=(44,55,66)
dict={'name': 'zhangsan', 'age': 30}
getTest(11, 22, 33, tuple, dict)

当我们还是按照上面的 *args 和 **kwargs 写法写时,发现参数 tuple 和 dict 被当做一个数据输出到了 *args 里,这是由于当我们传入 tuple 和 dict 时被当做了一个整体,我们可以在传入前先将其解构一下就可以了,如下:

 def getTest(a, b, c=123, *args, **kwargs):
print(a) #
print(b) #
print(c) #
print(args) # (44, 55, 66)
print(kwargs) # {'name': 'zhangsan', 'age': 30} tuple=(44,55,66)
dict={'name': 'zhangsan', 'age': 30}
getTest(11, 22, 33, *tuple, **dict)

如上,我们在传入参数的时候传入 *tuple 和 **dict 就可以解决了,但是如果我们在传入参数时和调用时都不加 * 不就相当于把整个变量作为参数了吗?如下:

 def getTest(a, b, c=123, tuple, dict):
print(a)
print(b)
print(c)
print(tuple)
print(dict) tuple=(44,55,66)
dict={'name': 'zhangsan', 'age': 30}
getTest(11, 22, 33, tuple, dict) # SyntaxError: non-default argument follows default argument

我们会发现不写 * 的话会报错,原因是当我们在函数中定义默认参数时,默认参数必须写在最后面,即 c=123 需写在最后面,如下:

 def getTest(a, b, tuple, dict, c=123):
print(a) #
print(b) #
print(c) #
print(tuple) # (44, 55, 66)
print(dict) # {'name': 'zhangsan', 'age': 30} tuple=(44,55,66)
dict={'name': 'zhangsan', 'age': 30}
getTest(11, 22, tuple, dict, 33)

但是如果参数中存在 * 的话默认参数不能写在最后面,如下:

 def getTest(a, b, *tuple, **dict, c=123):
print(a)
print(b)
print(c)
print(tuple)
print(dict) tuple=(44,55,66)
dict={'name': 'zhangsan', 'age': 30}
getTest(11, 22, *tuple, **dict, 33) # SyntaxError: invalid syntax

由此我们得出函数的传参顺序为:参数,默认参数,*args,**kwargs。

我们接下来看一下匿名函数。

python 使用 lambda 来创建匿名函数。

所谓匿名,意即不再使用 def 语句这样标准的形式定义一个函数。

  • lambda 只是一个表达式,函数体比 def 简单很多。
  • lambda的主体是一个表达式,而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去。
  • lambda 函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。
  • 虽然lambda函数看起来只能写一行,却不等同于C或C++的内联函数,后者的目的是调用小函数时不占用栈内存从而增加运行效率。

lambda 函数的语法只包含一个语句,如下:

lambda [arg1 [,arg2,.....argn]]:expression
 # 实现一个两数相加的匿名函数
sum = lambda num1, num2: num1 + num2
print(sum(10, 20)) #

Python 从入门到进阶之路(四)的更多相关文章

  1. Python 从入门到进阶之路(一)

    人生苦短,我用 Python. Python 无疑是目前最火的语言之一,在这里就不再夸他的 NB 之处了,本着对计算机编程的浓厚兴趣,便开始了对 Python 的自学之路,并记录下此学习记录的心酸历程 ...

  2. Python 从入门到进阶之路(七)

    之前的文章我们简单介绍了一下 Python 中异常处理,本篇文章我们来看一下 Python 中 is 和 == 的区别及深拷贝和浅拷贝. 我们先来看一下在 Python 中的双等号 == . == 是 ...

  3. Python 从入门到进阶之路(六)

    之前的文章我们简单介绍了一下 Python 的面向对象,本篇文章我们来看一下 Python 中异常处理. 我们在写程序时,有可能会出现程序报错,但是我们想绕过这个错误执行操作.即使我们的程序写的没问题 ...

  4. Python 从入门到进阶之路(五)

    之前的文章我们简单介绍了一下 Python 的函数,本篇文章我们来看一下 Python 中的面向对象. Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是 ...

  5. Python 从入门到进阶之路(三)

    在之前的文章我们介绍了一下 Python 中 if while for 的使用,本章我们来看一下 Python 中的变量类型. 在 Python 定义变量时的规则是 变量名 = 变量 ,Python ...

  6. Python 从入门到进阶之路(二)

    之前的文章我们对 Python 语法有了一个简单的认识,接下来我们对 Python 中的 if while for 做一下介绍. 上图为 if 判断语句的流程,无论任何语言,都会涉及到判断问题,if ...

  7. python快速入门及进阶

    python快速入门及进阶 by 小强

  8. Python 爬虫从入门到进阶之路(十四)

    之前的文章我们已经可以根据 re 模块,Xpath 模块和 BeautifulSoup4 模块来爬取网站上我们想要的数据并且存储在本地,但是我们并没有对存储数据的格式有要求,本章我们就来看数据的存储格 ...

  9. Python 爬虫从入门到进阶之路(四)

    之前的文章我们做了一个简单的例子爬取了百度首页的 html,我们用到的是 urlopen 来打开请求,它是一个特殊的opener(也就是模块帮我们构建好的).但是基本的 urlopen() 方法不支持 ...

随机推荐

  1. ubuntu16.04没有办法使用CRT,或者SSH工具的解决办法

    首先要明确一点,ubuntu16.04是默认没有安装SSH工具的 情况1 首先需要切换到root模式,然后在进行安装 设置root密码 sudo passwd 然后  sudo apt-get ins ...

  2. Fuchsia文章汇总

    今日,windows时代的十年已经过去,android/ios时代的十年也行将结束,下一个十年是谁的十年? 操作系统做为软件的基石,做为基础服务的基础,因为各层应用框架的层层封装,正在变的越来越透明, ...

  3. django admin配置以及使用

    admin组件使用 Django 提供了基于 web 的管理工具(django 2.0+, python3.6+). Django 自动管理工具是 django.contrib 的一部分.你可以在项目 ...

  4. Maven使用教程二:nexus私服搭建及使用

    nexus安装 从nexus官网 下载最新的安装包 1.打开命令行,切换到nexus-3.2.1-01/bin目录下,回车.例:C:\Nexus\nexus-3.2.1-01\bin 2.输入:nex ...

  5. JS---offset系列和scroll系列

    元素的样式属性是无法直接通过:对象.style.属性来获取(样式在style属性中设置)   offset系列: offsetLeft:距离左边位置的值 offsetTop:距离上面位置的值 offs ...

  6. bossplayersCTF 1: Vulnhub Walkthrough

    主机扫描: http://10.10.202.130/ <!--WkRJNWVXRXliSFZhTW14MVkwaEtkbG96U214ak0wMTFZMGRvZDBOblBUMEsK--> ...

  7. sql server的简单分页

    --显示前条数据 select top(4) * from students; --pageSize:每页显示的条数 --pageNow:当前页 )) sno from students); --带条 ...

  8. Bash脚本编程之脚本基础和bash配置文件

    脚本基础 参考资料:Shell Scripts (Bash Reference Manual) 不严谨地说,编程语言根据代码运行的方式,可以分为两种方式: 编译运行:需要先将人类可识别的代码文件编译成 ...

  9. 在Linux 中搭建 Mysql

    在本次搭建,出现了各种问题,一直解决不掉,建议各位小伙伴不要像我一样,像一个无头的苍蝇一样,这有问题就解决这个问题,没有意识本质实在的问题. 主要问题(加星,标重点):一定要看自己的linux 版本, ...

  10. System.out.println高并发下导致应用暂停

    今天在进行序列号压测的时候,通过调用genSeqId方法来获取序列号,100并发,16台压测机器,发现无论怎么压测,调用量达到140w左右的时候,此方法的ops直接掉到了0,具体图示如下: 从上图可以 ...