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 相关文章推荐
python判断windows隐藏文件的方法
Mar 21 Python
Python实现获取操作系统版本信息方法
Apr 08 Python
python 基础教程之Map使用方法
Jan 17 Python
解决seaborn在pycharm中绘图不出图的问题
May 24 Python
对Python中TKinter模块中的Label组件实例详解
Jun 14 Python
tesserocr与pytesseract模块的使用方法解析
Aug 30 Python
python实现视频读取和转化图片
Dec 10 Python
python操作gitlab API过程解析
Dec 27 Python
解决pycharm同一目录下无法import其他文件
Feb 12 Python
python新式类和经典类的区别实例分析
Mar 23 Python
如何学习Python time模块
Jun 03 Python
python实现简易版学生成绩管理系统
Jun 22 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
PHP新手上路(十四)
2006/10/09 PHP
dedecms 批量提取第一张图片最为缩略图的代码(文章+软件)
2009/10/29 PHP
删除无限分类并同时删除它下面的所有子分类的方法
2010/08/08 PHP
php数组函数序列之array_unshift() 在数组开头插入一个或多个元素
2011/11/07 PHP
IIS安装Apache伪静态插件的具体操作图文
2013/07/01 PHP
php中autoload的用法总结
2013/11/08 PHP
全面解读PHP的人气开发框架Laravel
2015/10/15 PHP
php基于自定义函数记录log日志方法
2017/07/21 PHP
javascript中的new使用
2010/03/20 Javascript
原创javascript小游戏实现代码
2010/08/19 Javascript
使用Plupload实现直接上传附件至七牛云存储
2014/12/26 Javascript
js获取内联样式的方法
2015/01/27 Javascript
简单实现IONIC购物车功能
2017/01/10 Javascript
swiper在vue项目中loop循环轮播失效的解决方法
2018/09/15 Javascript
详解js创建对象的几种方法及继承
2019/04/12 Javascript
javascript中contains是否包含功能实现代码(扩展字符、数组、dom)
2020/04/07 Javascript
JS this关键字在ajax中使用出现问题解决方案
2020/07/17 Javascript
ReactRouter的实现方法
2021/01/25 Javascript
python分析apache访问日志脚本分享
2015/02/26 Python
深入理解python对json的操作总结
2017/01/05 Python
Python爬虫之正则表达式的使用教程详解
2018/10/25 Python
解决pycharm的Python console不能调试当前程序的问题
2019/01/20 Python
django项目中使用手机号登录的实例代码
2019/08/15 Python
Windows下PyCharm2018.3.2 安装教程(图文详解)
2019/10/24 Python
python3 webp转gif格式的实现示例
2019/12/10 Python
python爬虫可以爬什么
2020/06/16 Python
利用html5 canvas动态画饼状图的示例代码
2018/04/02 HTML / CSS
美国电力供应商店/电气批发商:USESI
2018/10/12 全球购物
以工厂直接定价的传奇性能:Ben Hogan Golf
2019/01/04 全球购物
英国家居装饰品、户外家具和玻璃器皿购物网站:Rinkit.com
2019/11/04 全球购物
金融专业个人求职信
2013/09/22 职场文书
会计大学生职业生涯规划书范文
2014/01/13 职场文书
会计演讲稿范文
2014/05/23 职场文书
校庆标语集锦
2014/06/25 职场文书
党的群众路线查摆剖析材料
2014/10/10 职场文书
vue修饰符.capture和.self的区别
2022/04/22 Vue.js