`
网络接口
  • 浏览: 43782 次
文章分类
社区版块
存档分类
最新评论

Python中的默认参数值

 
阅读更多

不要使用可变对象作为函数的默认参数例如 list,dict,因为def是一个可执行语句,只有def执行的时候才会计算默认默认参数的值,所以使用默认参数会造成函数执行的时候一直在使用同一个对象,引起bug。

基本原理

 

在 Python 源码中,我们使用def来定义函数或者方法。在其他语言中,类似的东西往往只是一一个语法声明关键字,但def却是一个可执行的指令。Python代码执行的时候先会使用 compile 将其编译成 PyCodeObject.

 

PyCodeObject 本质上依然是一种静态源代码,只不过以字节码方式存储,因为它面向虚拟机。因此 Code 关注的是如何执行这些字节码,比如栈空间大小,各种常量变量符号列表,以及字节码与源码行号的对应关系等等。

 

PyFunctionObject 是运行期产生的。它提供一个动态环境,让 PyCodeObject 与运行环境关联起来。同时为函数调用提供一系列的上下文属性,诸如所在模块、全局名字空间、参数默认值等等。这是def语句执行的时候干的活。

 

PyFunctionObject 让函数面向逻辑,而不仅仅是虚拟机。PyFunctionObject 和 PyCodeObject 组合起来才是一个完整的函数。

 

下文翻译了一篇文章,有一些很好的例子。但是由于水平有限,有些不会翻译或者有些翻译有误,敬请谅解。如果有任何问题请发邮件到 acmerfight圈gmail.com,感激不尽

 

主要参考资料 书籍:《深入Python编程》 大牛:shell 和 Topsky

 

原文链接

 

Python对于函数中默认参数的处理往往会给新手造成困扰(但是通常只有一次)。

 

当你使用“可变”的对象作为函数中作为默认参数时会往往引起问题。因为在这种情况下参数可以在不创建新对象的情况下进行修改,例如 list dict。

 

    >>> def function(data=[]):

    ...     data.append(1)

    ...     return data

    ...

    >>> function()

    [1]

    >>> function()

    [1, 1]

    >>> function()

    [1, 1, 1]

 

像你所看到的那样,list变得越来越长。如果你仔细地查看这个list。你会发现list一直是同一个对象。

 

    >>> id(function())

    12516768

    >>> id(function())

    12516768

    >>> id(function())

    12516768

 

原因很简单: 在每次函数调用的时候,函数一直再使用同一个list对象。这么使用引起的变化,非常“sticky”。

为什么会发生这种情况?

 

当且仅当默认参数所在的“def”语句执行的时候,默认参数才会进行计算。请看文档描述

 

http://docs.python.org/ref/function.html

 

的相关部分。

 

"def"是Python中的可执行语句,默认参数在"def"的语句环境里被计算。如果你执行了"def"语句多次,每次它都将会创建一个新的函数对象。接下来我们将看到例子。

用什么来代替?

 

像其他人所提到的那样,用一个占位符来替代可以修改的默认值。None

 

    def myfunc(value=None):

        if value is None:

            value = []

        # modify value here

 

如果你想要处理任意类型的对象,可以使用sentinel

 

    sentinel = object()

 

    def myfunc(value=sentinel):

        if value is sentinel:

            value = expression

        # use/modify value here

 

在比较老的代码中,written before “object” was introduced,你有时会看到

 

    sentinel = ['placeholder']

 

    译者注:太水,真的不知道怎么翻译了。我说下我的理解 有时逻辑上可能需要传递一个None,而你的默认值可能又不是None,而且还刚好是个列表,列表不

    可以写在默认值位置,所以你需要占位符,但是用None,你又不知道是不是调用者传递过来的那个

 

正确地使用可变参数

 

最后需要注意的是一些高深的Python代码经常会利用这个机制的优势;举个例子,如果在一个循环里创建一些UI上的按钮,你可能会尝试这样去做:

 

    for i in range(10):

        def callback():

            print "clicked button", i

        UI.Button("button %s" % i, callback)

 

但是你却发现callback打印出相同的数字(在这个情况下很可能是9)。原因是Python的嵌套作用域只是绑定变量,而不是绑定数值的,所以callback只看到了变量i绑定的最后一个数值。为了避免这种情况,使用显示绑定。

 

    for i in range(10):

        def callback(i=i):

            print "clicked button", i

        UI.Button("button %s" % i, callback)

 

i=i把callback的参数i(一个局部变量)绑定到了当前外部的i变量的数值上。(译者注:如果不理解这个例子,请看http://stackoverflow.com/questions/233673/lexical-closures-in-python)

 

另外的两个用途local caches/memoization

 

    def calculate(a, b, c, memo={}):

        try:

            value = memo[a, b, c] # return already calculated value

        except KeyError:

            value = heavy_calculation(a, b, c)

            memo[a, b, c] = value # update the memo dictionary

        return value

 

(对一些递归算法非常好用)

 

对高度优化的代码而言, 会使用局部变量绑全局的变量:

 

    import math

 

    def this_one_must_be_fast(x, sin=math.sin, cos=math.cos):

        ...

 

这是如何工作的?

 

当Python执行一条def语句时, 它会使用已经准备好的东西(包括函数的代码对象和函数的上下文属性),创建了一个新的函数对象。同时,计算了函数的默认参数值。

 

不同的组件像函数对象的属性一样可以使用。上文用到的'function'

 

    >>> function.func_name

    'function'

    >>> function.func_code

    ", line 1>

    >>> function.func_defaults

    ([1, 1, 1],)

    >>> function.func_globals

    {'function': ,

    '__builtins__': ,

    '__name__': '__main__', '__doc__': None}

 

这样你可以访问默认参数,你甚至可以修改它。

 

    >>> function.func_defaults[0][:] = []

    >>> function()

    [1]

    >>> function.func_defaults

    ([1],)

 

然而我不推荐你平时这么使用。

 

另一个重置默认参数的方法是重新执行相同的def语句,Python将会和代码对象创建一个新的函数对象,并计算默认参数,并且把新创建的函数对象赋值给了和上次相同的变量。但是再次强调,只有你清晰地知道在做什么的情况下你才能这么做。

分享到:
评论

相关推荐

    第六章Python函数习题及答案--中文

    Python 函数习题及答案 -- 中文 本章节主要讲解了 Python ...本章节讲解了 Python 函数的基本概念和应用,包括函数的定义、函数的调用、函数的参数、函数的返回值等,同时也探讨了变量的范围和按值传递参数等问题。

    Python语言基础:函数的参数.pptx

    在Python中,函数的参数有四种: 必需参数 关键字参数 默认参数 不定长参数 必需参数是在函数调用时,须以正确的顺序传入,且调用时的数量必须和声明时的一样参数。 实例:定义一个printme函数,并定义一个必需参数...

    python下函数参数的传递(参数带星号的说明)

    在调用函数的过程中参数是如何被解析先看第一个问题,在python中函数参数的定义主要有四种方式: 1.F(arg1,arg2,…) 这 是最常见的定义方式,一个函数可以定义任意个参数,每个参数间用逗号分割,用这种方式定义的...

    Python中函数及默认参数的定义与调用操作实例分析

    本文实例讲述了Python中函数及默认参数的定义与调用操作。分享给大家供大家参考,具体如下: #coding=utf8 ''''' Python中的函数使用小括号调用。函数在调用之前必须先定义。 如果函数中没有return语句,就会自动...

    Python函数默认参数常见问题及解决方案

    一般来说,将参数值变化小的设置为默认参数。 python标准库实践 python内建函数: 函数签名可以看出,使用print(‘hello python’)这样的简单调用的打印语句,实际上传入了许多默认值,默认参数使得函数的调用变得...

    深入理解python中函数传递参数是值传递还是引用传递

    主要介绍了深入理解python中函数传递参数是值传递还是引用传递,涉及具体代码示例,具有一定参考价值,需要的朋友可以了解下。

    python中factor函数-Python基础教程.pdf

    python中factor函数_Python基础教程 6.4.5 参数收集的逆过程 假设有如下函数: def add(x,y): return x+y ⽐如说有个包含由两个相加的数字组成的元组: params = (1,2) 使⽤*运算符对参数进⾏"分配",不过是在调⽤⽽...

    Python中函数参数调用方式分析

    本文实例讲述了Python中函数参数调用方式。分享给大家供大家参考,具体如下: Python中函数的参数是很灵活的,下面分四种情况进行说明。 (1) fun(arg1, arg2, …) 这是最常见的方式,也是和其它语言类似的方式 下面...

    Python函数中参数是传递值还是引用详解

    主要介绍了深入了解Python函数中参数是传值还是传引用,在 C/C++ 中,传值和传引用是函数参数传递的两种方式,在Python中参数是如何传递的,需要的朋友可以参考下

    Python进阶-函数默认参数(详解)

    一、默认参数 python为了简化函数的调用,提供了默认参数机制: ...一般来说,将参数值变化小的设置为默认参数。 python标准库实践 python内建函数: print(*objects, sep=' ', end='\\n', file=sys

    理解Python中函数的参数

    对于函数的调用者来说,只需要知道如何传递正确的参数,以及函数将返回什么样的值就够了,函数内部的复杂逻辑被封装起来,调用者无需了解。 Python的函数定义非常简单,但灵活度却非常大。除了正常定义的必选参数外...

    Python中的多值参数

    大家在看Python中各个模块的函数时,经常会看到类似如下的情况: def plotxxx(a, b, *args, **kwargs): pass 关于其中的参数部分“*args, **kwargs”,许多人不是特别清晰,看到了许多介绍的文章,也觉得没有说的...

    Python中的默认参数详解

    不要使用可变对象作为函数的默认参数例如 list,dict,因为def是一个可执行语句,只有def执行的时候才会计算默认默认参数的值,所以使用默认参数会造成函数执行的时候一直在使用同一个对象,引起bug。 基本原理 在 ...

    Python科学计算与数据处理-Python函数.ppt

    在 Python 中,函数的定义语法为 `def function_name(arg1,arg2[,...]): statement [return value]`,其中 `function_name` 是函数名,`arg1,arg2,...` 是参数列表,`statement` 是函数体,`return value` 是返回值...

    Python中getMax函数def01.py

    定义一个数getMax()函数,返回三个数(从键盘输入的整数)中最大值。 def getMax(): num1=int(input("请在键盘上输入第1个整数:")) num2=int(input("请在键盘上输入第2个整数:")) num3=int(input("请在键盘上...

    Python中函数的初级知识.md

    对于函数的调用者来说,只需要知道如何传递正确的参数,以及函数将返回什么样的值就够了,函数内部的复杂逻辑被封装起来,调用者无需了解。 Python的函数定义非常简单,但灵活度却非常大。除了正常定义的必选参数外...

    python 函数的使用-python基础,python函数的使用说明,有python2的参考代码

    实参:函数调用时 的参数值 局部变量 函数内部声明的变量; 函数外具有相同名称的其他变量没有任何关系; 变量名称对于函数来说是局部的; “作用域”:所有变量的作用域是它们被定义的块,从它们的名称被定义的那...

    python中cos函数怎么用-Pythoncos()函数使用方法入门教程基础教程.pdf

    python中cos函数怎么⽤_Pythoncos()函数使⽤⽅法⼊门教 程基础教程 Python cos() 函数 描述 cos() 返回x的弧度的余弦值。 语法 以下是 cos() ⽅法的语法: import math math.cos(x) 注意:cos()是不能直接访问的,...

    python之函数架构-搭建房子的砖

    Python 的函数参数主要包含以下几种: 必选参数; 默认参数; 可变参数; 关键字参数。  必选参数也叫位置参数,是函数中最常用的参数。必选参数就是在调用函数的时候必须指定参数值。例如: 如果调用plus函数...

Global site tag (gtag.js) - Google Analytics