**函数的参数**
函数定义中的参数有以下几种:
* 必需参数(位置参数)
* 默认参数
* 关键字参数
* 不定长参数
* 不定长关键字参数
**必需参数(位置参数)**
* 必需参数(位置参数)必须以正确的顺序传入函数。调用时的数量必须和声明时的一样。
我们定义一个打招呼的函数
~~~
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
def myHello(yourname,myname):
'''定义招呼,需要依次传入对方的名字以及你的名字'''
print("Hello",yourname,"my name is",myname)
#第一次调用
myHello('lisa','airvip')
#第二次调用
myHello()
~~~
第一次调用,正确输出
~~~
Hello lisa my name is airvip
~~~
第二次调用,报了 缺少位置参数的错误
~~~
Traceback (most recent call last):
File "./test.py", line 10, in <module>
myHello()
TypeError: myHello() missing 2 required positional arguments: 'yourname' and 'myname'
~~~
**默认参数**
* 默认参数在调用时可以传入也可以不传入
* 默认参数在函数定义时必须在位置参数之后
我们修改下打招呼的函数
~~~
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
def myHello(yourname,myname = 'airvip'):
'''定义招呼,需要依次传入对方的名字以及你的名字'''
print("Hello",yourname,"my name is",myname)
#第一次调用
myHello('lisa','air')
#第二次调用
myHello('lisa')
~~~
第一次调用与第二次调用都会正确输出
~~~
Hello lisa my name is air
Hello lisa my name is airvip
~~~
可以看出添加了默认参数的函数调用相比只有位置参数的函数调用轻松多了。
**关键字参数**
* 关键字参数是相对于函数调用来说的,我们用位置参数的例子来说明。
* 使用关键字参数允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名匹配参数值。
~~~
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
def myHello(yourname,myname):
'''定义招呼,需要依次传入对方的名字以及你的名字'''
print("Hello",yourname,"my name is",myname)
#第一次调用
myHello('lisa','airvip')
#第二次调用
myHello('airvip','lisa')
#第三次调用 使用关键字
myHello(myname='airvip',yourname='lisa')
~~~
调用结果
~~~
#第一次调用
Hello lisa my name is airvip
#第二次调用
Hello airvip my name is lisa
#第三次调用 使用关键字
Hello lisa my name is airvip
~~~
我们不难发现,第一次调用与第三次调用返回的结果是一样的,然而第二次调用是没有使用关键字(定义函数时的形参),得到了与第一次和第三次调用不一样的结果。
**不定长参数**
* 在函数处理是可能不确定有几个参数,我们就可以定义成不定长参数。
* 习惯上使用 *args 来表示不定常参数,当然你也可以使用其他前面加星的变量表示不定长参数。
* 如果在函数调用时没有指定参数,它就是一个空元组。我们也可以不向函数传递未命名的变量。
* 不定长参数允许你传入 0 个或任意个参数,这些可变参数在函数调用时自动组装为一个 tuple。
以多个数字求和为例
~~~
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
def mySum(*args):
sum = 0
for i in args:
sum += i
print(sum)
#调用
mySum() #打印0
mySum(1,2,3) #打印6
mySum(*(1,2,3)) #打印6
mySum(*[1,2,3]) #打印6
~~~
**不定长关键字参数**
* 习惯上使用 **kwargs 来表示不定长关键字参数,当然你也可以使用其他前面加双星的变量表示不定长关键字参数。
* Python 解释器会把通过 **kwargs 传入的参数变成一个 dict 形式。
以收集用户信息为例
~~~
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
def userInfo(name,sex='男',*args,salary,**kwargs):
'''用户信息收集'''
print('用户信息'.center(20,'*'))
info = """
姓名:{_name}
性别:{_sex}
特征:{_args}
收入:{_salary}
其他: {_kwargs}
""".format(_name = name,_sex = sex,_args = args,_salary = salary,_kwargs = kwargs)
print(info)
userInfo('airvip','男','喜欢女','长得帅',salary='1000000',address='山东')
~~~
调用结果
~~~
********用户信息********
姓名:airvip
性别:男
特征:('喜欢女', '长得帅')
收入:1000000
其他: {'address': '山东'}
~~~
在 Python 中定义函数时,使用 必需参数(位置参数)、默认参数、不定长参数、关键字参数和不定长关键字参数,这5种参数的组合。但是参数定义的顺序必须是: 必需参数(位置参数)、默认参数、不定长参数、关键字参数和不定长关键字参数。
总结:
1. 使用了不定长参数默认参数就失效
2. *args 不定长参数,args 接收的是一个 tuple
3. **kwargs 不定长关键字参数,kwargs 接收的是一个 dict
4. 不定长参数既可以直接传入:func(1, 2, 3),又可以先组装 list 或 tuple ,再通过 *list 或 * tuple 传入
5. 不定长关键字参数既可以直接传入:func(a=1, b=2),又可以先组装 dict,再通过 **dict传入
**再谈默认参数**
默认参数很有用,但是使用不当又会产生不可思议的错误。
下面来探讨这个使用默认参数的例子
给列表末尾添加结束字符串:
~~~
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
def list_over(L = []):
L.append('Over')
return L
#第一次调用
print(list_over([1,2,3]))
#第二次调用
print(list_over([1,2,3]))
#第三次调用
print(list_over())
#第四次调用
print(list_over())
~~~
调用结果
~~~
[1, 2, 3, 'Over']
[1, 2, 3, 'Over']
['Over']
['Over', 'Over']
~~~
我们理想的结果是
第一次调用结果 等于 第二次调用
第三次调用结果 等于 第四次调用
然而,第三次调用结果 不等于 第四次调用 ,这是为什么呢?
因为 L 也是一个变量,该变量默认指向不变的内存地址空间,每次调用该函数,如果改变了该地址空间的值,则下次调用时,默认参数变量的内容就变了,但是该默认变量的指向没有发生改变,就造成了异常的结果。
所以,默认参数必须指向不变对象!
那问题来了,那该函数如何修改呢?
~~~
def list_over(L = None):
if L == None:
L = []
L.append('Over')
return L
~~~
这样无论使用默认参数调用多少次都不会改变默认变量 L 指向的内存空间的值了。
- 跟老司机学Python
- 了解Python
- 1、python简介
- 2、Python发展史
- 3、Python特点
- 4、Python解释器
- 入坑Python
- 1、Python环境搭建
- 2、设置环境变量
- 3、开始使用Python
- 4、运行Python程序
- 掌握Python基础
- Python基础知识
- Python运算符
- 算术运算符
- 比较运算符
- 赋值运算符
- 逻辑运算符
- 位运算符
- 成员运算符
- 身份运算符
- 运算符优先级
- Python的变量与常量
- Python数据类型
- Number数值
- String字符串
- List列表
- Tuple元组
- Dictionary字典
- Set集合
- Python流程控制语句
- 条件判断
- 循环控制
- Python函数
- 1、函数是什么
- 2、函数的定义
- 3、函数的参数
- 4、函数的调用
- 5、嵌套函数
- 6、递归函数
- 7、匿名函数
- 8、函数式编程
- 9、高阶函数
- 1、map
- 2、reduce
- 3、filter
- 4、sorted
- 10、返回函数
- 11、偏函数
- Python文件IO操作
- 标准输入输出
- 读写文件
- with读写文件
- Python高级特性
- 1、列表生成式
- 2、迭代器
- 3、生成器
- 4、装饰器
- Python模块初探
- 1、模块与包
- 2、创建模块
- 3、模块中的作用域
- 4、模块的导入
- Python面向对象编程
- 类与对象
- 类的定义及使用
- 面向对象特性
- 类中的访问域
- 查看对象详情
- Python面向对象进阶
- 类中的方法
- 类中的特殊成员
- 限制对象的属性
- 再聊多继承
- 装x式创建类
- 创建元类
- Python内置模块
- os模块
- sys模块
- random模块
- time模块
- datetime模块
- shutil模块
- collections模块
- base64模块
- json模块
- hashlib模块
- xml模块
- 1. SAX解析XML
- 2. DOM解析XML
- 3. ElementTree解析XML
- urllib模块
- logging模块
- re模块
- Python第三方模块
- Pillow与PIL
- Requests
- Tablib
- Xpinyin
- Chardet
- Pycurl
- Virtualenv
- Python操作数据库
- Mysql操作
- Sqllite操作
- Mongodb操作
- Redis操作
- Python的GUI编程
- Python中GUI的选择
- Tkinter
- wxPython
- Socket网络编程
- Socket网络编程简聊
- Socket内建方法
- TCP协议编程
- UDP协议编程
- TCP与UDP
- Python电子邮件
- SMTP发邮件
- POP3收邮件
- IMAP收邮件
- 进程线程
- 进程与线程
- 进程编程
- 使用进程池
- 进程间的通信
- 线程编程
- 使用线程锁
- Python的GIL
- Web编程
- WSGI介绍
- Web框架
- Flask使用
- 模板jinjia2使用
- 项目结构规划
- 异步与协程
- 概念扫盲
- 异步IO进化之路
- 协程是什么
- yield协程编程
- yield from
- asyncio
- async与await
- aiohttp之client
- aiphttp之server
- 网络爬虫
- 网络爬虫简聊
- Beautiful Soup模块的使用
- pyquery 模块的使用
- selenium模块的使用
- 爬取段子实例
- 错误与调试
- 错误
- 错误处理
- 抛出错误
- 高效的调试
- Python重要语句
- pass语句
- return语句
- Python开发必知
- pip使用详解
- 如何对列表进行迭代
- 如何对字典进行迭代
- 字符串格式化
- 知识扩展
- 网络模型
- GUI是什么