一、 可变数量参数

1、 概述

可变数量参数是指参数前带 * 的。如 *args.
比如,你想要通过一些参数信息来打印日志。使用固定参数如下:

12345678910111213
def log(message, values):if not values:print(message)else:values_str = ', '.join(str(x) for x in values)print('%s: %s' % (message, values_str))log('My numbers are', [1, 2])log('Hi there', [])>>>My numbers are: 1, 2Hi there

可以看出,当你没有values值传递的时候,你也不得不传递一个 [] 。

最好的做法就是没有值,第二个参数就留空。那么你能够在最后一个参数前加 * 来达到这样的效果。那么最后一个参数,你传递多少个值都是合法的。如下所示:

12345678910111213
def log(message, *values):  # The only differenceif not values:print(message)else:values_str = ', '.join(str(x) for x in values)print('%s: %s' % (message, values_str))log('My numbers are', 1, 2)log('Hi there')  # Much better>>>My numbers are: 1, 2Hi there

如果你已经有了一个列表变量,想要传递给像log这样的可选参数方法。你能够直接在列表变量前加 * 传递给方法。这表示让Python将列表中的元素项依次传递给方法。示例:

12345
favorites = [7, 33, 99]log('Favorite colors', *favorites)>>>Favorite colors: 7, 33, 99

2、 问题注意

接受可变位置的可变数量的参数有两个问题:

第一个问题就是可变参数在被传递到方法中时总是被转换为一个元组。这就意味着如果一个方法的参数是生成器前加 * 。那么该生成器参数将全部迭代完所有的元素,然后返回包含来自该生成器的所有元素组成的元组,这就有可能在数据量比较大的时候占用很大的内存,导致程序crash。

123456789101112
def my_generator():for i in range(10):yield idef my_func(*args):print(args)it = my_generator()my_func(*it)>>>(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)

第二个问题就是参数是位置对应的,传递的参数需要根据参数位置来传递,如果中间某个参数没有,那么可变参数中的元素将被填充到那个没有传参的参数中,具体示例如下:

12345678910111213
def log(sequence, message, *values):if not values:print('%s: %s' % (sequence, message))else:values_str = ', '.join(str(x) for x in values)print('%s: %s: %s' % (sequence, message, values_str))log(1, 'Favorites', 7, 33)      # New usage is OKlog('Favorite numbers', 7, 33)  # Old usage breaks>>>1: Favorites: 7, 33Favorite numbers: 7: 33

二、 关键字参数

1、 概述

跟其他程序语言一样,在Python中调用方法允许使用位置来传递参数。

1234
def remainder(number, divisor):return number % divisorassert remainder(20, 7) == 6

在Python中所有的位置参数也都可以使用关键字来传递,方法定义中的关键字也就是方法调用中的赋值变量。关键字参数能够以任意的位置来传递,也能够同位置参数混合使用。下面的调用都是等效的:

1234
remainder(20, 7)remainder(20, divisor=7)remainder(number=20, divisor=7)remainder(divisor=7, number=20)

2、 问题注意

位置参数必现在关键字参数之前被指定,看下面就是一个违法的调用:

1234
remainder(number=20, 7)>>>SyntaxError: non-keyword arg after keyword arg

每一个参数只能被指定一次:

1234
remainder(20, number=7)>>>TypeError: remainder() got multiple values for argument 'number'

3、 优点

使用关键字参数让程序可读性更好,通过参数名即可知道传递的参数的作用。

关键字参数可以指定默认的值,这对于某些逻辑是很有作用的。在调用的时候则可以不用传递参数,那么该方法将使用默认的值。示例:

12
def flow_rate(weight_diff, time_diff, period=1):return (weight_diff / time_diff) * period

调用:

12
flow_per_second = flow_rate(weight_diff, time_diff)flow_per_hour = flow_rate(weight_diff, time_diff, period=3600)

有利于程序的扩展性。可以对增加的关键字使用默认值,达到向后兼容的效果,不需要改动已有的代码,示例:

123
def flow_rate(weight_diff, time_diff,period=1, units_per_kg=1):return ((weight_diff * units_per_kg) / time_diff) * period

新增的调用逻辑:

12
pounds_per_hour = flow_rate(weight_diff, time_diff,period=3600, units_per_kg=2.2)

三、 动态默认参数

有时候你可能需要一个动态的默认参数值。先来看一个列子:

12345678910
def log(message, when=datetime.now()):print('%s: %s' % (when, message))log('Hi there!')sleep(0.1)log('Hi again!')>>>2014-11-15 21:10:10.371432: Hi there!2014-11-15 21:10:10.371432: Hi again!

我们发现这个时间是一样的,这是因为 datetime.now() 只执行了一次:当这个函数被定义的时候。这是因为当程序启动的时候,加载模块,这个模块包含的代码也被加载了,那么这个默认参数值就被确认了。

一般的做法是给这个参数赋 None 值,然后在代码文档注释中说明。具体动态默认值在程序中指定。示例:

12345678910
def log(message, when=None):"""Log a message with a timestamp.Args:message: Message to print.when: datetime of when the message occurred.Defaults to the present time."""when = datetime.now() if when is None else whenprint('%s: %s' % (when, message))

这时输出就是动态的参数值了:

1234567
log('Hi there!')sleep(0.1)log('Hi again!')>>>2014-11-15 21:10:10.472303: Hi there!2014-11-15 21:10:10.573395: Hi again!

使用None作为参数默认值时很重要的,特别是当你的参数是可变的时候。比如,你想要加载一个data,并使用json编码。如果编码失败,你想要返回一个空的字典。你可能这样做:

12345
def decode(data, default={}):try:return json.loads(data)except ValueError:return default

这个效果之前一个列子一样,所有的调用使用的都是同样的默认值,这会导致无法预期的效果:

12345678910
foo = decode('bad data')foo['stuff'] = 5bar = decode('also bad')bar['meep'] = 1print('Foo:', foo)print('Bar:', bar)>>>Foo: {'stuff': 5, 'meep': 1}Bar: {'stuff': 5, 'meep': 1}

可以发现,两个对象的值都是一样的,改变一个影响了另一个。这是因为两个都是同一个默认值,指向的是同一个对象。

1
assert foo is bar

使用 None 作为默认值可以解决这个问题

1234567891011121314
def decode(data, default=None):"""Load JSON data from a string.Args:data: JSON data to decode.default: Value to return if decoding fails.Defaults to an empty dictionary."""if default is None:default = {}try:return json.loads(data)except ValueError:return default

现在调用可以发现是正确的了:

12345678910
foo = decode('bad data')foo['stuff'] = 5bar = decode('also bad')bar['meep'] = 1print('Foo:', foo)print('Bar:', bar)>>>Foo: {'stuff': 5}Bar: {'meep': 1}

四、 强制使用关键字参数

比如,你在处理两个数相除时,有时候可能想要忽略 ZeroDivisionError 异常,返回无穷大。有时候想要忽略 OverflowError 异常,返回0.

1234567891011121314
def safe_division(number, divisor, ignore_overflow,ignore_zero_division):try:return number / divisorexcept OverflowError:if ignore_overflow:return 0else:raiseexcept ZeroDivisionError:if ignore_zero_division:return float('inf')else:raise

调用:

12345
result = safe_division(1, 10**500, True, False)print(result)>>>0.0

或者:

12345
result = safe_division(1, 0, False, True)print(result)>>>inf

但是你会发现只看调用,是非常不直观的,不知道每个参数是什么意思,这时可以用关键字参数来指示:

1234
def safe_division_b(number, divisor,ignore_overflow=False,ignore_zero_division=False):# ...

调用:

12
safe_division_b(1, 10**500, ignore_overflow=True)safe_division_b(1, 0, ignore_zero_division=True)

但是还有一个问题就是,这个关键字参数是可选,你任然可以使用位置参数来调用:

1
safe_division_b(1, 10**500, True, False)

那么可不可以强制调用者使用关键字呢?在Python3中可以这样做:在参数中加一个 * 参数,表示之前的参数是位置参数,之后的参数是关键字参数,必须强制表明。

1234
def safe_division_c(number, divisor, *,ignore_overflow=False,ignore_zero_division=False):# ...

现在使用位置参数来调用将报错:

1234
safe_division_c(1, 10**500, True, False)>>>TypeError: safe_division_c() takes 2 positional arguments but 4 were given

正确调用:

123456
safe_division_c(1, 0, ignore_zero_division=True)  # OKtry:safe_division_c(1, 0)except ZeroDivisionError:pass  # Expected

五、 可变数量关键字参数

将数量不定的可变数量关键字参数传递给方法时,可以使用 ** 参数。

123456789
def print_args(*args, **kwargs):print 'Positional:', argsprint 'Keyword:   ', kwargsprint_args(1, 2, foo='bar', stuff='meep')>>>Positional: (1, 2)Keyword:    {'foo': 'bar', 'stuff': 'meep'}

调用的时候,会将传递的所有的关键字参数传递给 kwargs 参数,Python会将其转化成一个字典。

六、 参数顺序

几种方法参数的定义顺序为:位置参数,关键字参数,非关键字可变长参数(*args),可变数量关键字参数(**kwargs)。

根据传递的参数顺序来依次匹配,先逐级匹配,如果还有剩余的参数再匹配下一级参数。

博客:https://tunsuy.github.io/

github:https://github.com/tunsuy

高效Python编程之方法参数相关推荐

  1. Python编程错误:参数错误([_ctypes.COMError: (-2147024809, ‘参数错误。‘, (None, None, None, 0, ...

    Python编程错误:参数错误([_ctypes.COMError: (-2147024809, '参数错误.', (None, None, None, 0, None))] 在Python编程中,程 ...

  2. python自学路线-自学python编程的方法路线

    怎么自学python编程 如何自学Python编程?一堆的Python教程却感觉无从下手呢?我想这应该是很多Python初学者正在纠结的问题. 今天想要分享给大家的是如何自学Python编程,学习这件 ...

  3. 自学python-自学python编程的方法路线

    怎么自学python编程 如何自学Python编程?一堆的Python教程却感觉无从下手呢?我想这应该是很多Python初学者正在纠结的问题. 今天想要分享给大家的是如何自学Python编程,学习这件 ...

  4. python编程方式_自学python编程的方法路线

    怎么自学python编程 如何自学Python编程?一堆的Python教程却感觉无从下手呢?我想这应该是很多Python初学者正在纠结的问题. 今天想要分享给大家的是如何自学Python编程,学习这件 ...

  5. python字符串format方法参数解释,一文秒懂!Python字符串格式化之format方法详解

    一文秒懂!Python字符串格式化之format方法详解 一文秒懂!Python字符串格式化之format方法详解 format是字符串内嵌的一个方法,用于格式化字符串.以大括号{}来标明被替换的字符 ...

  6. python采用那种编程模式_使用Mixin设计模式进行Python编程的方法讲解

    class BetterSimpleItemContainer(object, DictMixin): def __getitem__(self, id): return self.data[id] ...

  7. Python编程学习:让函数更加灵活的*args和**kwargs(设计不同数量参数的函数)的简介、使用方法、经典案例之详细攻略

    Python编程学习:让函数更加灵活的*args和**kwargs(设计不同数量参数的函数)的简介.使用方法.经典案例之详细攻略 目录 *args和**kwargs(设计不同数量的参数函数)的简介 1 ...

  8. 站长在线经典Python题:使用Python编程思想解决鸡兔同笼的问题的4种方法

    欢迎你来到站长在线的Python题库,鸡兔写完Python教程以后,还是来一个Python的题目吧!想来想去,还是写一个经典的题目为好,作为本栏目的第一个题目.我就想到了比较热门的题目<鸡兔同笼 ...

  9. python编程100例-python100例,python经典例题

    肯定有用,练习就是实战.对于刚学习编程的同学,我觉得跟着例子学习,会有很大的进步.至少让你熟悉语法和理解编程的一些技巧.当你能熟练掌握python编程的方法后,你需要学习一些第三方库,python的第 ...

最新文章

  1. 使用LaTeX排版如何方便地引用多篇参考文献(不使用插件)
  2. [Swust OJ 404]--最小代价树(动态规划)
  3. python画直方图成绩分析-使用Python绘制直方图和正态分布曲线
  4. 类的笔记整理__7-10__
  5. websocket 代理tcp_netty实现websocket请求实战
  6. 英伟达账号登录邮箱验证收不到_【硬核教学】解决登录230锁定
  7. python绘图设置标题出现乱码_解决python2 绘图title,xlabel,ylabel出现中文乱码的问题...
  8. Lind.DDD.RedisClient~对StackExchange.Redis调用者的封装及多路复用技术
  9. 计算机图形相关输出设备,计算机图形输出设备.ppt
  10. python 数据分析 实际案例_python在实际工作中运用的案例
  11. (32)FPGA米勒型状态机设计(三段式)(第7天)
  12. android系统(9)---Android Sensor 体系架构
  13. element-UI:el-table 表格排序
  14. js 禁用和解除禁用按钮_js禁用button,js 将某个按钮禁用5秒钟
  15. 8位并行左移串行转换电路_单片机试题
  16. 市场营销学9——产品策略
  17. luogu3426 [POI2005]SZA-Template 后缀树
  18. 速记计算机键盘,键盘字母排列的速记公式
  19. Redis(2) redis-cli 客户端操作Redis - 常用命令大全
  20. 结对编程遇到猪队友,“你用的才是中华田园敏捷!”

热门文章

  1. C语言输出1-100中3的倍数
  2. 数电/数字电子技术期末考前突击复习(小白稳过,看这一篇就够了)
  3. 苹果cmsv10首涂模板第十三套宽屏大轮播支持DIY的自适应模板
  4. 扫描件如何转换成word文档?扫描件转可编辑文本技巧
  5. python处理数据的一些代码
  6. 大数据技术和产业的创新与发展,需要从哪几个方面入手
  7. 校园食堂明厨亮灶智能视频监控 YOLOv5
  8. 飞书信(Facebook Messenger)是什么?
  9. 手机怎样快速获取root权限,手机怎样快速获取root权限密码
  10. SharePoint中跨列表查询