简体   繁体   English

Python 函数:可选参数评估一次?

[英]Python function: Optional argument evaluated once?

Python Tutorial 4.7.1. Python 教程4.7.1。 Default Argument Values states the following: 默认参数值声明如下:

Important warning: The default value is evaluated only once.重要警告:默认值仅评估一次。 This makes a difference when the default is a mutable object such as a list, dictionary, or instances of most classes.当默认值是可变对象(例如列表、字典或大多数类的实例)时,这会有所不同。 For example, the following function accumulates the arguments passed to it on subsequent calls:例如,以下函数在后续调用中累积传递给它的参数:

 def f(a, L=[]): L.append(a) return L print f(1) print f(2) print f(3)

This will print这将打印

[1] [1, 2] [1, 2, 3]

I don't quite understand the meaning of "evaluated only once" in terms of memory management.在内存管理方面,我不太明白“仅评估一次”的含义。 Apparently, the default value of the function is evaluated once when the function is first called and stored in a separate memory address even after the function has ended.显然,函数的默认值在函数第一次被调用时被评估一次,并存储在一个单独的内存地址中,即使在函数结束后也是如此。 (according to my understanding, after the function ended, all local variables should be freed?) (按照我的理解,函数结束后,所有局部变量都应该被释放?)

Am I correct?我对么?

In Python, functions are objects too, and the defaults are stored with the function object.在 Python 中,函数也是对象,默认值与函数对象一起存储。 Defaults are not locals;默认值不是本地人; it is just that when the function is called, the arguments are bound to a default when not given an explicit value.只是当函数被调用时,如果没有给出明确的值,参数会被绑定到默认值。

When Python encounters a def <functionname>(<arguments>): statement, it creates a function object for you there and then ;当 Python 遇到def <functionname>(<arguments>):语句时,它会在那里为您创建一个函数对象,然后; this is 'definition time';这是“定义时间”; the function is not called but merely created.该函数不被调用,而只是被创建。 It is then that defaults are evaluated and stored, in an attribute on the function object.然后在函数对象的属性中评估和存储默认值。

Then when you call the function, the defaults have already been created and are used when you didn't provide a more concrete value for the argument.然后,当您调用该函数时,默认值已经创建并在您没有​​为参数提供更具体的值时使用。 Because the defaults are stored with the function object, you get to see changes to mutable objects between function calls.由于默认值与函数对象一起存储,因此您可以在函数调用之间看到可变对象的更改。

The locals are still cleared up of course, but as they are references (all identifiers in Python are), the objects they were bound to are only cleared up if nothing else is referencing them anymore either.当然,局部变量仍然会被清除,但由于它们是引用(Python 中的所有标识符都是),因此它们绑定到的对象只有在没有其他对象再引用它们时才会被清除。

You can take a look a the defaults of any function object:您可以查看任何函数对象的默认值:

>>> 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

The foo() function has a __defaults__ attribute, a tuple of default values to use when no values for the arguments have been passed in. You can see the mutable list change as the function is called, and because the function returns the eggs list, you can also see that it is the exact same object as the second value in that tuple. foo()函数有一个__defaults__属性,当没有传入参数值时使用的默认值元组。您可以看到可变列表在函数调用时发生变化,并且因为函数返回eggs列表,您还可以看到它该元组中的第二个值完全相同

If you don't want your defaults to be shared and instead need a new value for a parameter every time the function is called, but the parameter is not given, you need to set the default value to a sentinel object.如果您不希望共享默认值,而是在每次调用函数时都需要一个参数的新值,但没有给出参数,则需要将默认值设置为哨兵对象。 If your parameter is still set to that sentinel in the function body, you can execute code to set a fresh default value.如果您的参数仍然设置为函数体中的那个哨兵,您可以执行代码来设置一个新的默认值。 None is usually the best choice: None通常是最好的选择:

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

If it should be possible to use None as a non-default value, use a singleton sentinel created beforehand:如果应该可以使用None作为非默认值,请使用预先创建的单例标记:

_sentinel = object()

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

A function is just an object in python, that is created using the def syntax.函数只是 Python 中的一个对象,它是使用def语法创建的。 Default values are stored within the function object when the function is defined, and they are not re-evaluated later.默认值在定义函数时存储在函数对象中,以后不会重新计算。

This is sometimes used to create function variables that persist to subsequent invocations.这有时用于创建持续到后续调用的函数变量 You can use the __defaults__ methods to check what the default values are for your function.您可以使用__defaults__方法来检查您的函数的默认值。

A common way to initialize new objects instead of reusing the same is:初始化新对象而不是重用相同对象的常用方法是:

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

    L.append(a)
    return L

You can check this page for more details.您可以查看此页面了解更多详情。

The function that you have defined f is an object in its own regard.您定义的函数f就其本身而言是一个对象。 When you define defaults, these defaults are bound to the function that you have created.当您定义默认值时,这些默认值将绑定到您创建的函数。

You can see this in action:你可以看到这一点:

>>> 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],)

edit, further, you can see that the list container does not change either:进一步编辑,您可以看到列表容器也没有更改:

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

On each subsequent call, the default list (" L ") of your f function will have your a value appended.在每次后续调用中,您的f函数的默认列表(“ L ”)都会附加您的a值。

Sorry this answer was meant for a different question, but I'll leave it here as a reference if anyone who wants to look at it.对不起,这个答案是针对另一个问题的,但如果有人想看它,我会把它留在这里作为参考。 Define once means that at the first point when the code is executed, the default variable gets assigned to an object which is retained within the function object itself.定义一次意味着在代码执行的第一点,默认变量被分配给保留在函数对象本身中的对象。

Notice only 1 object address gets printed, the default list object is used.注意只打印 1 个对象地址,使用默认列表对象。

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

Notice 2 different object addresses are printed, when you perform L=[] within the function, you are binding L to a different list object, therefore the default list object does not get change.注意打印了 2 个不同的对象地址,当您在函数内执行 L=[] 时,您将 L 绑定到不同的列表对象,因此默认列表对象不会更改。

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

The function above is basically the same as the one below except it uses the None object instead of a empty list object.上面的函数与下面的函数基本相同,只是它使用 None 对象而不是空列表对象。

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 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM