Python - 入站出站参数

发布于 2025-01-03 17:00:57 字数 440 浏览 1 评论 0原文

我在《Python 专家编程》中读到过有关这种边缘情况的内容。检查这段代码:

def f(arg={}):
    arg['3'] = 4
    return arg

>>> print f()
{'3': 4}
>>> res = f()
>>> res['4'] = 'Still here'
>>> print f()
{'3': 4, '4': 'Still here'}

我不清楚为什么最后一次调用 f 时(在保存其返回值之后),而不是将 arg 分配给空字典(因为它是在没有参数的情况下调用的) ,它保留旧的参考。

书中是这样说的:“如果在参数中创建了一个对象,那么如果函数返回该对象,参数引用仍然有效”。

我明白“事情就是这样”,但为什么会这样呢?

I've read in Expert Python Programming about this edge case. Check this code:

def f(arg={}):
    arg['3'] = 4
    return arg

>>> print f()
{'3': 4}
>>> res = f()
>>> res['4'] = 'Still here'
>>> print f()
{'3': 4, '4': 'Still here'}

It's not clear to me why when f gets called the last time (after its return value has been saved), instead of assigning arg the empty dict (since it was called with no arguments), it keeps the old reference.

The book says so: "if an object is created within the arguments, the argument reference will still be alive if the function returns the object".

I understand that "this is the way it works", but why so?

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

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

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

醉生梦死 2025-01-10 17:00:57

因为默认参数仅在函数被求值和创建时求值一次(它们是函数定义的一部分,例如可以通过 inform.getargspec 获取)。

由于它们是函数的一部分,因此对函数的每次调用都将具有默认值的相同实例。如果它是一个不可变的值,这不是问题,但一旦它是可变的,它就会成为一个问题。

相同的“特征”存在于类定义中,给定一个类定义:

class A(object):
    foo = {}

调用

x = A() 
y = A()
x.foo['bar'] = "baz"

... 将使 y.foo['bar'] 计算为“baz”,因为 x 和 y 具有相同富。
这就是为什么成员初始化应该在init而不是类体中完成。

Because the default arguments are evaluated once only, when the function is evaluated and created (they are part of the function defenition and can be fetched through inspect.getargspec, for example).

Since they are part of the function, every call to the function will have the same instance of the default value. This is not a problem if it is an immutable value, but as soon as it is mutable it can become a gotcha.

The same 'feature' exist in class defenitions, given a class defenition:

class A(object):
    foo = {}

calling

x = A() 
y = A()
x.foo['bar'] = "baz"

...would give that y.foo['bar'] evaluates to "baz", since x and y has the same foo.
This is why member initialization should be done in init instead of the class body.

戏舞 2025-01-10 17:00:57

您的问题是默认为可变参数(在本例中为字典):

def f(arg={}):
    arg['3'] = 4
    return arg

应该是:

def f(arg=None):
    arg = arg if arg is not None else {}
    arg['3'] = 4
    return arg

yields:

>>> print f()
{'3': 4}
>>> res = f()
>>> res['4'] = 'Still here'
>>> print f()
{'3': 4}

就像您所期望的那样。

这里的问题是默认参数是在第一次定义/解析函数时计算的,而不是在调用它们时计算的。这只是您需要注意的 python 解析器的细微差别。

要了解原因,请查看“Least Astonishment”和可变默认参数< /a>

Your problem is defaulting to a mutable argument (dictionary in this case):

def f(arg={}):
    arg['3'] = 4
    return arg

should be:

def f(arg=None):
    arg = arg if arg is not None else {}
    arg['3'] = 4
    return arg

yields:

>>> print f()
{'3': 4}
>>> res = f()
>>> res['4'] = 'Still here'
>>> print f()
{'3': 4}

like you'd expect.

The issue here is the default arguments are evaluated when the function is first defined/parsed, not when they are called. It's just a nuance of the python parser that you need to be aware of.

For the why, check out "Least Astonishment" and the Mutable Default Argument

懒的傷心 2025-01-10 17:00:57

默认参数在声明函数时创建一次,因此每次调用 f() 都会获得相同的字典实例,该实例一开始为空。这能回答问题吗?

The default parameter gets created once, when the functon is declared, so every call to f() gets the same instance of a dictionary, which starts out empty. Does that answer the question?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文