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

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中函数参数的四种类型:必需参数、关键字参数、默认参数和不定长参数。 1. **必需参数**: 必需参数是在定义函数时明确指定的参数,调用函数时必须按顺序提供这些参数。如果缺少任何一个...

    Python中函数参数设置及使用的学习笔记

    ### Python中函数参数设置及使用的深入解析 #### 一、参数和共享引用 在Python中,函数参数通过赋值的方式传递。当函数被调用时,实际上是在共享对象的引用。这种特性对于不可变对象(如整数)来说,其在函数内部...

    Python函数中的默认参数:深入指南与实践应用

    默认参数允许我们为函数的参数指定默认值,如果调用时没有提供相应的参数值,则会自动使用这些默认值。这种特性在提高代码复用性、简化函数调用以及编写更灵活的代码方面非常有用。本文将详细介绍如何在Python函数中...

    向python脚本传递参数(例子)

    在Python编程中,能够从命令行接收参数是一项非常实用的功能。本文将深入探讨如何使用`sys.argv`来接收命令行参数,并通过一个具体的示例——过滤文本文件中的特定关键字——来展示这一功能的具体应用。 #### 一、...

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

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

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

    Python函数的默认参数是编程中常见的特性,它允许我们在调用函数时省略某些参数的值,这些参数将使用在函数定义时设定的默认值。然而,如果不正确地使用默认参数,可能会导致一些意外的问题。以下是一些关于Python...

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

    在Python编程语言中,`factor`函数通常是指用于因式分解整数的函数,但这在提供的文本中并未直接介绍。然而,我们可以从描述和部分内容中提取出几个关键知识点: 1. **参数收集与解包**: - Python允许在函数定义...

    python函数实验报告.doc

    2. **函数参数**: - 函数可以接受参数,如`isPrime`函数中的`v`,用于传递值到函数内部进行处理。 - 参数类型可以是整数、字符串等,例如`demo`函数接收一个字符串`v`,统计其中的大写字母、小写字母、数字和其他...

    Python 函数的参数-在函数内部使用方法修改可变参数会影响外部实参

    Python也可用于可定制化软件中的扩展程序语言。Python丰富的标准库,提供了适用于各个主要系统平台的源码或机器码。 Python还被语言流行指数的编译器Tiobe将它被评为最受欢迎的编程语言,20多年来首次将Python置于...

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

    在探讨Python函数参数传递机制之前,我们首先需要理解Python中变量与对象的关系。不同于C/C++等语言,Python中的变量更像是对象的引用或标签,而不是一个单独的内存空间。因此,理解Python中的参数传递方式,必须先...

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

    本文将通过具体的代码示例和内存地址分析,帮助读者更深入地理解Python函数参数传递的本质。 #### Python中参数传递的基本原理 Python函数参数传递本质上是基于对象的引用。这意味着当我们将一个对象作为参数传递...

    c++调用Python函数(并返回数据).zip

    4. **准备参数**:根据Python函数的参数类型,我们需要创建相应的Python对象作为参数。例如,如果函数需要一个整数参数,我们可以使用`PyLong_FromLong()`创建一个整数对象。 5. **调用Python函数**:使用`PyObject...

    Python应用开发-函数默认参数.pptx

    在Python编程语言中,函数是组织代码的重要方式,而函数的默认参数则是提高代码复用性和灵活性的一个关键特性。在《Python应用开发-函数默认参数》的主题中,我们将深入探讨如何使用和理解Python函数的默认参数。 ...

    Python中的函数(课件)

    在Python编程语言中,函数是组织良好、可重用的代码块,它们执行特定任务并可能接收输入(参数)和返回结果(返回值)。函数在软件开发中扮演着至关重要的角色,因为它们有助于提高代码的模块化和可读性。 **函数的...

    深入讲解Python函数中参数的使用及默认参数的陷阱

    总之,理解Python函数参数的使用,包括必选参数、默认参数、可变参数和关键字参数,以及如何利用它们编写清晰、灵活的代码,对于Python开发者来说至关重要。同时,对递归和尾递归的掌握也能帮助解决一些复杂问题。

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

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

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

    Python函数的默认参数是编程中常见的特性,它允许在不提供所有必需参数的情况下调用函数。这大大简化了代码,特别是在处理重复性任务时。然而,如果不正确地使用默认参数,可能会导致意料之外的结果。下面我们将深入...

    Python函数.md

    #### 四、函数参数 ##### 1、位置参数与关键字参数 - **位置参数**:按照参数的位置顺序进行传递。例如: ```python def test(a, b, c): print(a) print(b) print(c) test(1, 2, 3) # 输出1 2 3 ``` - **...

    8.表达式求值_python/表达式求值_

    描述中提到的“5行代码,用python匿名函数实现表达式求值”,指的是利用Python的lambda函数和eval()内置函数来简洁地完成这个功能。 **lambda函数**是Python中的一个简洁方式,用于创建匿名函数,即没有名字的函数...

Global site tag (gtag.js) - Google Analytics