返回介绍

默认和可变对象

发布于 2024-01-29 22:24:16 字数 1413 浏览 0 评论 0 收藏 0

默认参数是在def语句运行时评估并保存的,而不是在这个函数调用时。从内部来讲,Python会将每一个默认参数保存成一个对象,附加在这个函数本身。

这也就是通常我们所想要的:因为默认参数是在def时被评估的,如果必要的话,它能够从整个作用域内保存值,但是因为默认参数在调用之间都保存了一个对象,必须对修改可变的默认参数十分小心。例如,下面的函数使用了一个空列表作为默认参数,并在函数每次调用时都对它进行了改变。

有些人把这种行为当作一种特性。因为可变类型的默认参数在函数调用之间保存了它们的状态,从某种意义上讲它们能够充当C语言中的静态本地函数变量的角色。在一定程度上,它们工作起来就像全局变量,但是它们的变量名对于函数来说是本地变量,而且不会与程序中的其他变量名发生冲突。

尽管这样,对于大多数人来说,这看起来就像是一个陷阱,特别第一次遇到这样的情况的时候。在Python中有更好的办法在调用之间保存状态(例如,使用类,这将在第6部分进行讨论)。

此外,可变类型默认参数记忆起来比较困难(理解起来也不容易)。它们的值取决于默认对象构建的时间。在上一个例子中,其中只有一个列表对象作为默认值,这个列表对象是在def语句执行时被创建的。不会每次函数调用时都得到一个新的列表,所以每次新的元素加入后,列表会变大,对于每次调用,它都没有重置为空列表。

如果这不是你想要的行为的话,在函数主体的开始对默认参数进行简单的拷贝,或者将默认参数值的表达式移至函数体内部。只要值是存在于在代码中,而这部分代码在函数每次运行时都会执行的话,你就会每次都得到一个新的对象。

顺便提一下,这个例子中的if语句可以被赋值语句x=x or[]来代替,这个赋值语句将会利用Python的or语句返回操作符对象中的一个的特性:如果没有参数传入的话,x将会默认为None,所以or将会返回右边的空列表。

尽管如此,这还不是完全相同的。如果是一个空列表被传入,or表达式将会导致函数扩展并返回一个新创建的列表,而不是像if版本那样扩展并返回传入的列表。(表达式变成[]or[],将会设置为右边空列表的值。参看第12章中的相关内容,如果你想不起来为什么的话)。真正的程序也许都需要这两种行为。

如今,以一种较少令人混淆的方式来实现可变默认值效果的另一种方式,是使用我们在第19章讨论过的函数属性:

该函数的名称对于函数自身来说是全局的,但是,它不需要声明,因为它在函数内部是不会直接修改的。这并不是总是以完全相同的方式使用,但是,当这样编写代码的时候,一个对象到函数的附加总是更加明确(并且肯定更容易理解)。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文