开发者

question about python names using a default parameter value

开发者 https://www.devze.com 2023-01-11 00:36 出处:网络
I was reading this today: http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html#default-parameter-values and I can\'t seem to understand what\'s happening under the hood.

I was reading this today: http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html#default-parameter-values and I can't seem to understand what's happening under the hood.

def bad_append(new_item, a_list=[]):
    a_list.append(new_item)
    return a_list

The problem here is that the default value of a_list, an empty list, is evaluated at function definition time. So every time you call the function, you get the same default value. Try it several times:

I guess first of all, when is the function definition stage? Is it an initialization stage just before the actual main function executes?

My original thinking was that the name a_list gets discarded right after the function runs so whatever [] mutated to will be garbage collected. Now, I think that a_list is not discarded at all since it's only a name bound to the object [] so it never gets garbage collected because a_list is still bound to it. But then again, I'm wondering how I still get the same default value instead of a new []. Can someone straighten this out for me?

Tha开发者_Go百科nks!


when is the function definition stage?

Look at "Function definitions" in the Python reference:

Default parameter values are evaluated when the function definition is executed. This means that the expression is evaluated once, when the function is defined, and that that same “pre-computed” value is used for each call. This is especially important to understand when a default parameter is a mutable object, such as a list or a dictionary: if the function modifies the object (e.g. by appending an item to a list), the default value is in effect modified. This is generally not what was intended. A way around this is to use None as the default, and explicitly test for it in the body of the function, e.g.:

def whats_on_the_telly(penguin=None):
    if penguin is None:
        penguin = []
    penguin.append("property of the zoo")
    return penguin

The parameters are evaluated when the function definition is executed. If this is in a module, it happens when the module is imported. If it's in a class, it's when the class definition runs. If it's in a function, it happens when the function executes. Remember that a Python module is evaluated from top to bottom, and doesn't automatically have an explicit "main function" like some languages.

For example, if you put the function definition inside a function, you get a new copy of the function each time:

>>> def make_function():
...     def f(value=[]):
...             value.append('hello')
...             return value
...     return f
... 
>>> f1 = make_function()
>>> f2 = make_function()
>>> f1()
['hello']
>>> f1()
['hello', 'hello']
>>> f2()
['hello']

The function definition creates a new function object, assigns it various properties including the code, formal parameters, and default values, and stores it in a name in the scope. Typically this only happens once for any given function, but there are cases where a function's definition can be executed again.

My original thinking was that the name a_list gets discarded right after the function runs so whatever [] mutated to will be garbage collected.

Inside the body of the function, the name a_list is available to the code. So the name, and the value it is pointing to, must both still be available. It is stored in the func_defaults attribute of the function.

But then again, I'm wondering how I still get the same default value instead of a new [].

Because the [] is evaluated only when the function is defined, not when it is called, and the name a_list points to the same object even across repeated calls. Again, if you want the alternative behavior, use something immutable like None and check for it.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号