资讯专栏INFORMATION COLUMN

python 默认参数问题及一个应用

firim / 3707人阅读

摘要:源自我的博客里面一个常见的陷阱就是函数的默认参数问题。默认参数的一个应用先看下面的一个经典的例子简略版本结果是而不是,原因就是闭包的延迟绑定。结果自然就是这就是默认参数的一个应用。

</>复制代码

  1. 源自: 我的博客

python 里面一个常见的陷阱就是函数的默认参数问题。如下:

</>复制代码

  1. def func(mylist = []):
  2. mylist.append(1)
  3. return mylist

以下的执行结果如下:

</>复制代码

  1. print func()
  2. print func()
  3. print func()
  4. print func(["a"])
  5. print func()

结果如下:

</>复制代码

  1. [1]
  2. [1, 1]
  3. [1, 1, 1]
  4. ["a", 1]
  5. [1, 1, 1, 1]

如此结果, 前面三个可以看出 如果没有指定参数的话, 每次调用函数时候, 调用的mylist 是同一个对象。这是因为函数的默认参数,是在代码编译成PyCodeObject的时候, 就已经创建了对象指针,并且存在该函数的func_default内。 以后在代码运行,调用函数的时候,如果没有指定参数的话, 每次调用的话, 该参数变量都是代码编译阶段的变量指针所指定的对象。

</>复制代码

  1. print func.func_default

此时结果就是:

</>复制代码

  1. ([1, 1, 1, 1], )

默认参数分为两种情况:

默认参数值是不可变对象

此时函数的 func_default 一直指向该不变对象, 如果函数内部修改了该变量, 那么该默认参数会指向一个新的不可变对象.

不过func_default 不变。 而每次调用函数都是读取func_default, 因此每次执行都一样。

</>复制代码

  1. In [30]: def func2(var = 1):
  2. ....: var += 1
  3. ....: return var
  4. ....:
  5. In [31]: func2()
  6. Out[31]: 2
  7. In [32]: func2()
  8. Out[32]: 2
  9. In [34]: func2.func_defaults
  10. Out[34]: (1,)

默认参数是可变对象,比如 list, dict, class

这种情况下,如果在函数内修改了指针所指的对象(并未创建新的对象), 那么 func_default 就会改变。这正是开始的mylist发生变化的原因。看下面的例子,:

</>复制代码

  1. In [35]: def func(mylist = []):
  2. ....: mylist = [] #这里 创建了新的对象,
  3. mylist.append(1)
  4. return mylist
  5. In [44]: func()
  6. Out[44]: [1]
  7. In [45]: func.func_defaults
  8. Out[45]: ([],)
  9. 由于创建了对象, mylist 只是作为一个 新建对象的别名存在, 后面在修改已经与 func_default 无关了。


默认参数的一个应用

先看下面的一个经典的例子:

</>复制代码

  1. def outer():
  2. res = []
  3. for i in range(4):
  4. def inner(j):
  5. return j * i
  6. res.append(inner)
  7. return res
  8. print [m(2) for m in outer()]
  9. #简略版本:
  10. def multipliers():
  11. return [lambda x : i * x for i in range(4)]
  12. print [m(2) for m in multipliers()]

结果是 [6, 6, 6, 6] , 而不是 [0, 2, 4, 6], 原因就是闭包的延迟绑定。另外函数绑定的是变量而不是绑定数值。当循环结束了,i的值已经是3, 此时结果都是6. 一个解决方法便是,使用默认参数绑定数值。如下改动:

</>复制代码

  1. def outer():
  2. res = []
  3. for i in range(4):
  4. def inner(j, i = i):
  5. return j * i
  6. res.append(inner)
  7. return res
  8. print [m(2) for m in outer()]
  9. #简略版本:
  10. def multipliers():
  11. return [lambda x, i = i : i * x for i in range(4)]
  12. print [m(2) for m in multipliers()]

这样的话, 利用默认参数在代码编译的时候,便把参数写到函数的func_default中, 就可以绑定0,1,2,3了。结果自然就是

</>复制代码

  1. [0, 2, 4, 6]

这就是默认参数的一个应用。

</>复制代码

  1. 上述还有一个生成器修改的方式

</>复制代码

  1. def multipliers():
  2. return (lambda x : i * x for i in range(4)) #修改成生成器
  3. print [m(2) for m in multipliers()]

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/37787.html

相关文章

  • 机器学习应用——导学part

    摘要:之机器学习第一弹。机器学习是发展中应用广泛的一个领域。库集成了一些常用的机器学习方法在进行机器学习任务时并不需要实现算法只需要简单的调用库中提供的模块就能完成大多数的机器学习任务。 ...

    edgardeng 评论0 收藏0
  • Python——基本数据类型(模块2: time库的使用)(实例3:文本进度条)

    摘要:前言本篇主要介绍基本数据类型,以文本进度条为例,介绍库的使用。 前言 本篇主要介绍基本数据类型,以文本进度条为例,介绍time库的使用。 并在最后对蟒蛇绘制的代码进...

    Jenny_Tong 评论0 收藏0
  • python入门 django入门 (一)

    摘要:本人年开发经验,现就职于电信,因工作需要学习,记录自己的学习记录。 本人java10年开发经验,现就职于电信,因工作需要学习python,记录自己的学习记录。后面也...

    hzc 评论0 收藏0
  • 100 个基本 Python 面试问题第二部分(21-40)

    摘要:为我们提供了许多内置函数,例如并提供了创建用户定义函数的能力。会将该变量视为函数级作用域中的局部变量。回到目录中函数的用途是什么是中的内置函数之一。请注意,这种类型的参数语法不允许将命名参数传递给函数。函数接受一个称为的可选参数。 ...

    2450184176 评论0 收藏0
  • 通读Python官方文档之wsgiref(未完成)

    摘要:一般来说,这一例行程序用于处理请求的每一部分,例如把路径作为一系列字典键值进行处理。,必须是按照中所规定地键值元组列表。行为时回车换行。这个包装器也可能用模块指明那些有问题的,但不完全违反的行为。 wsgirf-WSGI功能及参考实现 源码:Lib/wsgiref Web服务器网关接口(Web Server Gateway Interface, WSGI),是用Python写的一个服务...

    mumumu 评论0 收藏0

发表评论

0条评论

firim

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<