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实现命令行有道词典的方法示例
Jan 31 Python
Python检测网络延迟的代码
May 15 Python
Python Socket编程之多线程聊天室
Jul 28 Python
Python设计模式之享元模式原理与用法实例分析
Jan 11 Python
python射线法判断检测点是否位于区域外接矩形内
Jun 28 Python
Python计算一个点到所有点的欧式距离实现方法
Jul 04 Python
python Kmeans算法原理深入解析
Aug 23 Python
Python实现滑动平均(Moving Average)的例子
Aug 24 Python
520使用Python实现“我爱你”表白
May 20 Python
Selenium python时间控件输入问题解决方案
Jul 22 Python
详解Python小数据池和代码块缓存机制
Apr 07 Python
Python破解极验滑动验证码详细步骤
May 21 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
IIS6的PHP最佳配置方法
2007/03/19 PHP
关于IIS php调用com组件的权限问题
2012/01/11 PHP
PHP函数strip_tags的一个bug浅析
2014/05/22 PHP
php对象在内存中的存在形式分析
2015/02/03 PHP
codeigniter实现get分页的方法
2015/07/10 PHP
自写的利用PDO对mysql数据库增删改查操作类
2018/02/19 PHP
thinkphp5框架实现数据库读取的数据转换成json格式示例
2019/10/10 PHP
异步加载script的代码
2011/01/12 Javascript
jquery插件制作 图片走廊 gallery
2012/08/17 Javascript
jquery实现简易的移动端验证表单
2015/11/08 Javascript
JS封装cookie操作函数实例(设置、读取、删除)
2015/11/17 Javascript
javascript基于prototype实现类似OOP继承的方法
2015/12/16 Javascript
对js eval()函数的一些见解
2016/08/15 Javascript
jquery 多个radio的click事件实例
2016/12/03 Javascript
Js经典案例的实例代码
2018/05/10 Javascript
微信小程序实现侧边分类栏
2019/10/21 Javascript
react组件基本用法示例小结
2020/04/27 Javascript
浅谈JavaScript中this的指向问题
2020/07/28 Javascript
Windows系统配置python脚本开机启动的3种方法分享
2015/03/10 Python
Python中分数的相关使用教程
2015/03/30 Python
Python中转换角度为弧度的radians()方法
2015/05/18 Python
详谈Python2.6和Python3.0中对除法操作的异同
2017/04/28 Python
python使用pyqt写带界面工具的示例代码
2017/10/23 Python
Python3 模块、包调用&路径详解
2017/10/25 Python
Pycharm 操作Django Model的简单运用方法
2018/05/23 Python
python判断列表的连续数字范围并分块的方法
2018/11/16 Python
linux环境下安装python虚拟环境及注意事项
2020/01/07 Python
python定义类的简单用法
2020/07/24 Python
CSS+jQuery实现的在线答题功能
2015/04/25 HTML / CSS
Canvas制作旋转的太极的示例
2018/03/09 HTML / CSS
日本亚马逊官方网站:Amazon.co.jp
2020/04/14 全球购物
结构工程研究生求职信
2013/10/13 职场文书
幼儿园大班家长评语
2014/04/17 职场文书
婚内分居协议书范文
2014/11/26 职场文书
实习员工转正的评语汇总,以备不时之需
2019/12/17 职场文书
pytorch中的model.eval()和BN层的使用
2021/05/22 Python