Python参数类型以及常见的坑详解


Posted in Python onJuly 08, 2019

导语

由于之前遇到过几次有关于参数类型的坑,以及经常容易把一些参数类型搞混淆,现在做一下有关参数类型的总结记录以及对之前踩坑经历的分析。

参数类型

首先我们列举一下有关于Python的参数类型,以及实际上的运用和原理。

  • 位置参数(必选参数)
  • 默认参数
  • 可变参数
  • 关键字参数

位置参数(必选参数)

首先是位置参数,同时也被称作必选参数,位置参数很好理解,只要记住这点:

在函数定义时直接给定的此参数名称,调用时按照参数的位置顺序,依次赋予参数值。

示例:

def person_info(name, age):
  print("My name is %s, I am %s years old" % (name, age))

person_info("zhangsan", "49")  
# name,age都是位置参数,按照位置顺序,函数中依次接收参数值。

默认参数

默认参数,默认参数存在许多便利的地方,但是同时也存在许多坑,等到后面我们再去仔细分析下为什么存在这些坑,以下几点我们需要注意的:

  • 可以为一个或者多个参数指定默认值,当调用函数时可以不用传入该参数值,大大降低函数调用的难度。
  • 当需要用传入的参数值代替默认参数的默认值时,可以按照参数位置顺序传入,同时也可以指定参数名传入。

示例:

def person_info(name, age, sex='man'):
  print("My name is %s, I am %s years old, I am %s" % (name, age, sex))

person_info('zhangsan', '15')
person_info('lisi', '15', 'women')
person_info('lisi', '20', sex='women')

可变参数

可变参数,顾名思义就是传入的参数数量是可变的:

可变参数在实际中,传入的数量可以是任意多个,但也可以没有。

而可变参数会在传入函数内部时,是一个tuple的形式。

示例:

def add(*numbers):
  sum = 0
  for i in numbers:
    sum+=i
  return sum

print(add(1,3,4,2,1,4,1,3)) 

numbers=[2,3,4,1,5]
add(*numbers)
# 当传入的参数为list时,会将list中所有的元素作为可变参数,传进去

关键字参数

当可变参数在传入0个或者任意个参数时,这些可变参数会在函数调用时自动组装成一个tuple。而关键字参数也允许你传入0个或者任意个含参数名的参数,这些关键字参数会函数内部自动组装为一个dict。调用函数时,可以只传入必选参数。

扩展函数的功能,**kwargs

示例:

def person_info(**kw):
  for key,value in kw.items():
    print(key, value)

person_info(name='zhangsan', age=15)
person = {'name': 'zhangsan', 'age': 13}
person_info(**person)

命名关键字参数

对于关键字参数,函数的调用者可以传入任意不受限制的关键字参数。但是针对到底传入了哪些参数,就需要通过函数内部分析检查。所以命名关键字参数就是限制传入的参数的名字,只能传我已命名关键字参数。

  • 命名关键字参数需要一个特殊分隔符*,分隔符后面的参数会被视为命名关键字参数。
  • 当函数中已经存在一个可变参数,后面跟着的命名关键字参数就不需要一个*特殊分隔符——“”**。
  • 命名关键参数可以有默认值,从而简化调用。
  • 命名关键参数必须传入一个参数名,这和位置参数不同。如果没有传入参数名,调用将会报错。

示例:

def person_info(name, *, age, sex):
  print(name, age, sex)

def person_info2(name, *args, age, sex):
  for i in args:
    print(i)
  print(name, age, sex)

person_info('zhangsan', age=12, sex='man')
person_info2('zhangsan', 'sksks', 'ssk', age=13, sex='man')

参数组合调用规则

在python定义函数过程中,可以用位置参数、默认参数、可变参数、关键字参数、命名关键字参数。这五种参数都可以通过组合使用。需要注意的是:

这五种参数定义的顺序必须是:位置参数、默认参数、可变参数、命名关键字参数、关键字参数。

位置参数和默认参数组合

def Person(name, age=20):
  print(name,age)

Person('zhangsan')
Person('zhangsan', 20)

位置参数、默认参数、可变参数组合

def Person(name, age=20, *args):
  for i in args:
    print(i)
  print(name, age)

Person('zhangsan')
Person('zhangsan', 22, "Beijing")
Person('zhangsan', age=22, 'Shanghai')

位置参数、默认参数、可变参数、命名关键字参数组合

def Person(name, age=20, *args, city, **kwargs):
  for i in args:
    print(i)
  for key,value in kwargs.items():
    print(key, value)
  print(name, age, city)

Person('zhangsan', age=12, 'Author', city='Shanghai', company='Shanghai Software')

关于参数定义的一些坑

默认参数陷阱

关于默认参数陷阱的问题,我们先来看一看一个示例:

def Book(book, book_list=[]):
  print(id(book_list))
  book_list.append(book)
  for book in book_list:
    print(book)
  print(id(book_list))  

test = Book("First One")

输出的结果:

Python参数类型以及常见的坑详解

这个输出的结果应该是意料之中,现在我们这时候再调用Book()方法,看看会发生什么:

Python参数类型以及常见的坑详解

这时候输出结果,竟然把之前的First one都输出,看了他们的id,发现都是同一块内存地址,这时候就开始纳闷了,那么来找找出现这种状况的原因。

经过查阅官方资料发现,这是一段Python官方文档给出的解释:

Important warning: The default value is evaluated only once. This makes a difference when the default is a mutable object such as a list, dictionary, or instances of most classes. For example, the following function accumulates the arguments passed to it on subsequent calls:

我们来看看解释分析下,Python官方文档给出的理由就是Python对默认值只计算一次,对于可变对象,在后续调用的情况下会累积传递给他们。而list、dict等这种都属于可变对象。

那么对于这种默认值陷阱,我们是该如何避免造成一些不必要的麻烦呢?大致有两种解决方法:

  • 避免使用可变对象作为默认值。
  • 在参数定义的时候可以使用None对象作为占位符。

对于第二种方法:

def Book(book, book_list=None):
  print(book_list)
  if book_list is None:
    book_list = []
  book_list.append(book)
  for book in book_list:
    print(book)
  print(id(book_list)) 

test1 = Book('First one')
test2 = Book('Second one')

测试结果:

Python参数类型以及常见的坑详解

慎用变长参数

前面已经介绍过了,Python是支持可变长度的参数列表,可以在函数定义参数时使用*args和**kwargs两个特殊的语法来实现。

那为什么要说慎用变长参数,我总结了一下有以下几个原因:

使用过于灵活。比如在我上面有关不同类型参数组合使用的示例中,在位置参数和默认参数在的情况下,还有可变参数、关键字参数、命名关键字参数。这就很容易是的这个函数的签名不够清晰,调用者需要花费时间去了解你这个方法该如何调用。所以这就很容易使得团队开发中效率低效。

另外一个原因,如果一个函数的列表过于长,虽然可以通过使用*args, **kwargs来简化函数,但同时也意味这个函数或许有更好的实现方式,有重构的必要。

说完了要慎用,在说说看我们常用的变长参数的使用场景:

  • 为函数添加一个装饰器。
  • 如果参数的数目不确定的时候,可以考虑使用变长参数。比如读取一些配置文件中的配置项时。
  • 用来实现函数的多态,或者在继承情况下子类需要调用父类的某些方法。

总结

关于的Python参数类型就写到这里了,刚开始学Python的时候,经常被函数定义的参数类型搞懵,后面看了一些教程,自己在写一些脚本的时候遇到的一些坑,并且在看一些大牛分析背后的原理,后面感觉收获良多。后面干脆想把自己学习过程遇到的东西都整理一下,做个记录,加深理解。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python3 适合初学者学习的银行账户登录系统实例
Aug 08 Python
教你学会使用Python正则表达式
Sep 07 Python
对python3 一组数值的归一化处理方法详解
Jul 11 Python
Django 多环境配置详解
May 14 Python
python的等深分箱实例
Nov 22 Python
用Python实现校园通知更新提醒功能
Nov 23 Python
Python matplotlib实时画图案例
Apr 23 Python
python爬虫快速响应服务器的做法
Nov 24 Python
python urllib和urllib3知识点总结
Feb 08 Python
Python爬虫之用Xpath获取关键标签实现自动评论盖楼抽奖(二)
Jun 07 Python
python用海龟绘图写贪吃蛇游戏
Jun 18 Python
python实现剪贴板的操作
Jul 01 Python
python里运用私有属性和方法总结
Jul 08 #Python
python设计微型小说网站(基于Django+Bootstrap框架)
Jul 08 #Python
python字符串查找函数的用法详解
Jul 08 #Python
python提取log文件内容并画出图表
Jul 08 #Python
Python OpenCV 使用滑动条来调整函数参数的方法
Jul 08 #Python
使用Python opencv实现视频与图片的相互转换
Jul 08 #Python
python基于paramiko将文件上传到服务器代码实现
Jul 08 #Python
You might like
DEDE采集大师官方留后门的删除办法
2011/01/08 PHP
使用PHP强制下载PDF文件示例
2014/01/17 PHP
php操作mongodb封装类与用法实例
2018/09/01 PHP
PHP 超级全局变量相关总结
2020/06/30 PHP
Javascript在IE下设置innerHTML时出现未知的运行时错误的解决方法
2011/01/12 Javascript
window.open不被拦截的实现代码
2012/08/22 Javascript
javascript实现仿腾讯游戏选择
2015/05/14 Javascript
js文本框走动跑马灯效果代码分享
2015/08/25 Javascript
基于javascript实现九九乘法表
2016/03/27 Javascript
js日期相关函数dateAdd,dateDiff,dateFormat等介绍
2016/09/24 Javascript
Ajax实现不刷新取最新商品
2017/03/01 Javascript
实现图片首尾平滑轮播(JS原生方法—节流)
2017/10/17 Javascript
使用store来优化React组件的方法
2017/10/23 Javascript
vue 中directive功能的简单实现
2018/01/05 Javascript
AngularJS监听ng-repeat渲染完成的方法
2018/03/20 Javascript
利用Python自动监控网站并发送邮件告警的方法
2016/08/24 Python
python3 pillow生成简单验证码图片的示例
2017/09/19 Python
Python创建普通菜单示例【基于win32ui模块】
2018/05/09 Python
Python之列表的插入&替换修改方法
2018/06/28 Python
一行Python代码制作动态二维码的实现
2019/09/09 Python
大家都说好用的Python命令行库click的使用
2019/11/07 Python
Python 3.9的到来到底是意味着什么
2020/10/14 Python
Canvas高级路径操作之拖拽对象的实现
2019/08/05 HTML / CSS
Right-on官方网站:日本知名的休闲服装品牌
2019/07/12 全球购物
EJB的角色和三个对象
2015/12/31 面试题
成教毕业生自我鉴定
2013/10/23 职场文书
本科毕业自我鉴定
2014/03/20 职场文书
城管综合整治方案
2014/05/01 职场文书
党支部换届选举方案
2014/05/08 职场文书
2015年春节标语口号
2014/12/09 职场文书
致我们终将逝去的青春观后感
2015/06/10 职场文书
安全知识竞赛主持词
2015/06/30 职场文书
Nginx缓存设置案例详解
2021/09/15 Servers
利用js实现简单开关灯代码
2021/11/23 Javascript
动态规划之使用备忘录来改进Javascript函数
2022/04/07 Javascript
深入理解 Golang 的字符串
2022/05/04 Golang