Python函数:可选参数计算一次?

Python函数:可选参数计算一次?,python,Python,Python教程说明了以下内容: 重要警告:默认值仅计算一次。这就不同了 当默认值为可变对象时,例如列表、字典或most的实例 上课。例如,下面的函数累积上传递给它的参数 后续电话: def f(a, L=[]): L.append(a) return L print f(1) print f(2) print f(3) 这会打印出来 [1] [1, 2] [1, 2, 3] 我不太明白“只评估一次”在内存管理方面的含义。显然,当函数第一次被调用并存储在单独的内存地址中时,

Python教程说明了以下内容:

重要警告:默认值仅计算一次。这就不同了 当默认值为可变对象时,例如列表、字典或most的实例 上课。例如,下面的函数累积上传递给它的参数 后续电话:

def f(a, L=[]):
    L.append(a)
    return L

print f(1)
print f(2)
print f(3)
这会打印出来

[1]
[1, 2]
[1, 2, 3]
我不太明白“只评估一次”在内存管理方面的含义。显然,当函数第一次被调用并存储在单独的内存地址中时,即使在函数结束后,函数的默认值也会被计算一次。(据我了解,函数结束后,所有局部变量都应该释放?)


我说的对吗?

在Python中,函数也是对象,默认值与函数对象一起存储。默认值是而不是局部变量;只是在调用函数时,参数在没有给出显式值的情况下绑定到默认值

当Python遇到
def():
语句时,它会在那里为您创建一个函数对象;这是“定义时间”;函数不是被调用的,只是被创建的。然后,在函数对象的属性中计算并存储默认值

然后,当您调用该函数时,默认值已经创建,并且在您没有为参数提供更具体的值时使用。由于默认值与函数对象一起存储,因此可以在函数调用之间看到可变对象的更改

当然,局部变量仍然会被清除,但由于它们是引用(Python中的所有标识符都是),因此它们绑定到的对象只有在没有其他对象引用它们时才会被清除

您可以查看任何函数对象的默认值:

>>> def foo(bar='spam', eggs=[]):
...     eggs.append(bar)
...     return eggs
... 
>>> foo.__defaults__
('spam', [])
>>> foo()
['spam']
>>> foo.__defaults__
('spam', ['spam'])
>>> foo() is foo.__defaults__[1]
True
foo()
函数有一个
\uuuuu defaults\uuuuu
属性,这是一个默认值元组,在没有传入参数值时使用。在调用函数时,您可以看到可变列表的变化,并且由于函数返回
eggs
列表,因此您还可以看到它与该元组中的第二个值是完全相同的对象

如果您不希望共享默认值,而是需要在每次调用函数时为参数指定一个新值,但未指定参数,则需要将默认值设置为sentinel对象。如果您的参数仍然设置为函数体中的sentinel,则可以执行代码来设置新的默认值<代码>无通常是最佳选择:

def foo(bar='spam', eggs=None):
    if eggs is None:
        eggs = []
如果可以使用
None
作为非默认值,请使用事先创建的单例sentinel:

_sentinel = object()

def foo(bar='spam', eggs=_sentinel):
    if eggs is _sentinel:
        eggs = []

函数只是python中的一个对象,它是使用
def
语法创建的。定义函数时,默认值存储在函数对象中,以后不会重新计算

这有时用于创建保存到后续调用的函数变量。您可以使用
\uuuu defaults\uuuu
方法检查函数的默认值

初始化新对象而不是重用新对象的常用方法是:

def f(a, L=None):
    if L is None:
        L = []

    L.append(a)
    return L

您可以查看更多详细信息。

您定义的函数本身就是一个对象。定义默认值时,这些默认值将绑定到已创建的函数

您可以看到这一点:

>>> def f(a, L=[]):
...    L.append(a)
...    return L

>>> print id(f)
4419902952

>>> print f.__defaults__
([],)
>>> f(1)
[1]

>>> print id(f)
4419902952

>>> print f.__defaults__
([1],)
进一步编辑,您可以看到列表容器不会更改:

>>> print id(f.__defaults__[0])
4419887544
>>> f(2)
[1, 2]
>>> print id(f.__defaults__[0])
4419887544

在随后的每次调用中,
f
函数的默认列表(“
L
”)将附加
a
值。

对不起,这个答案是针对不同的问题的,但是如果有人想看它,我会把它留在这里作为参考。定义一次意味着在执行代码的第一个点,默认变量被分配给一个对象,该对象保留在函数对象本身中

请注意,仅打印1个对象地址,使用默认列表对象

  def f(a, L=[]):
    print("id default: ", id(L))
    L.append(a)
    print("id used: ", id(L)
    return L
注意,打印了两个不同的对象地址,当您在函数中执行L=[]时,您将L绑定到不同的列表对象,因此默认列表对象不会得到更改

def f(a, L=[]):
    print("id default: ", id(L))
    if L == []:
        L = []
    L.append(a)
    print("id used: ", id(L))      
    return L 
上面的函数与下面的函数基本相同,只是它使用None对象而不是空的list对象

def f(a, L=None):
    print("id default", id(L))
    if L is None:
        L = []
   L.append(a) 
   print("id used: ", id(L))      
   return L 

不是“第一次调用时”,而是“定义时”。密切相关,但不是重复:这与工作环境无关。这是关于何时计算函数默认值的问题。你是对的,我误解了这个问题,但是,添加一种获得所需行为的方法通常是有用的。当然,但这就是目的;e、 g.这篇文章最初是作为一个复制品结束的。如果你现在看到这个问题,它已经链接了教程的相关部分(也有解决方案)。这个答案需要解释