Python 从入门到进阶之路(四)
之前的文章我们简单介绍了一下 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 从入门到进阶之路(四)的更多相关文章
- Python 从入门到进阶之路(一)
人生苦短,我用 Python. Python 无疑是目前最火的语言之一,在这里就不再夸他的 NB 之处了,本着对计算机编程的浓厚兴趣,便开始了对 Python 的自学之路,并记录下此学习记录的心酸历程 ...
- Python 从入门到进阶之路(七)
之前的文章我们简单介绍了一下 Python 中异常处理,本篇文章我们来看一下 Python 中 is 和 == 的区别及深拷贝和浅拷贝. 我们先来看一下在 Python 中的双等号 == . == 是 ...
- Python 从入门到进阶之路(六)
之前的文章我们简单介绍了一下 Python 的面向对象,本篇文章我们来看一下 Python 中异常处理. 我们在写程序时,有可能会出现程序报错,但是我们想绕过这个错误执行操作.即使我们的程序写的没问题 ...
- Python 从入门到进阶之路(五)
之前的文章我们简单介绍了一下 Python 的函数,本篇文章我们来看一下 Python 中的面向对象. Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是 ...
- Python 从入门到进阶之路(三)
在之前的文章我们介绍了一下 Python 中 if while for 的使用,本章我们来看一下 Python 中的变量类型. 在 Python 定义变量时的规则是 变量名 = 变量 ,Python ...
- Python 从入门到进阶之路(二)
之前的文章我们对 Python 语法有了一个简单的认识,接下来我们对 Python 中的 if while for 做一下介绍. 上图为 if 判断语句的流程,无论任何语言,都会涉及到判断问题,if ...
- python快速入门及进阶
python快速入门及进阶 by 小强
- Python 爬虫从入门到进阶之路(十四)
之前的文章我们已经可以根据 re 模块,Xpath 模块和 BeautifulSoup4 模块来爬取网站上我们想要的数据并且存储在本地,但是我们并没有对存储数据的格式有要求,本章我们就来看数据的存储格 ...
- Python 爬虫从入门到进阶之路(四)
之前的文章我们做了一个简单的例子爬取了百度首页的 html,我们用到的是 urlopen 来打开请求,它是一个特殊的opener(也就是模块帮我们构建好的).但是基本的 urlopen() 方法不支持 ...
随机推荐
- JavaScript原型 补充
js原型 // 构造函数 = 类 function A(){} let a1 = new A(); // 添加原型 num => 类似于属性 A.prototype.num = 100; con ...
- 电商设计V1(一):软件工程设计
软件工程设计的方式方法 多视图法: 全面分析软件方方面面的问题 尽早地发现和排除项目风险与不确定因素 从不同角度去展现要设计的软件系统 为项目进行不同的干系人提供指导: 逻辑架构描述系统功能,并指导系 ...
- CSS 盒子模型、RestCSS、浮动、定位
盒子模型 边框:border 左边框:border-left 右边框:border-right 上边框:border-top 下边框:border-bottom 复合样式:border 边框颜色:bo ...
- NGUI 源码分析- AnchorPoint
AnchorPoint 是 UIRect 的一个内部类,此处规定作为基准的那个对象称为锚点对象,基准对象对应的矩形框称为目标框,当前对象对应的矩形框称为源框. public class AnchorP ...
- 记录MyBatis text类型 查询 更新 数据是null
数据库表里面存在text或者blob字段.逆向工程自动生成的MyBatis的xml中会多出几个以withBlobs结尾的方法和resultMap 此时查询数据或者更新数据的使用仍然使用selectBy ...
- DFA敏感词过滤实现
package test.java.com.odianyun.util.sensi; import java.util.*; /** * 敏感词处理工具 - DFA算法实现 * * @author s ...
- ASP.NET Core身份验证
asp.net core 身份验证 本文旨在演示如果使用内置的 identity 实现 asp.net core 的身份验证,不会进行其它扩展.本文将通过最简单的代码演示如何进行登录和身份验证操作. ...
- ASP.NET Aries 高级开发教程:行内编辑事件怎么新增数据到后台(番外篇)
前提: 今天又网友又提出了一个问题,说行内编辑保存之前,怎么新增一些数据提交到后台? 对方说看了源码,也没找到怎么处理,这里就写文给解答一下. 解答: 于是我看了一眼源码,只能说你没找到地方: 第12 ...
- Unicode、UTF-8、Big Endian、Little Endian、GBK、UCS-2
一.Unicode.UCS.GBK 1.开始计算机只在美国用.八位的字节一共可以组合出256(2的8次方)种不同的状态.把这些0×20以下的字节状态称为”控制码”.他们又把所有的空 格.标点符号.数字 ...
- springboot 打包jar 运行找资源文件
使用如下方式读取文件:ClassPathResource cpr = new ClassPathResource("static/ok.png");byte[] bdata = F ...