Why the “mutable default argument fix” syntax is so ugly, asks python newbie

前端 未结 8 628
悲&欢浪女
悲&欢浪女 2020-11-30 09:00

Now following my series of \"python newbie questions\" and based on another question.

Prerogative

Go to http://python.net/~goodger/projects/pyco

相关标签:
8条回答
  • 2020-11-30 09:28

    Default arguments are evaluated at the time the def statement is executed, which is the probably the most reasonable approach: it is often what is wanted. If it wasn't the case, it could cause confusing results when the environment changes a little.

    Differentiating with a magic local method or something like that is far from ideal. Python tries to make things pretty plain and there is no obvious, clear replacement for the current boilerplate that doesn't resort to messing with the rather consistent semantics Python currently has.

    0 讨论(0)
  • 2020-11-30 09:28

    I've edited this answer to include thoughts from the many comments posted in the question.

    The example you give is flawed. It modifies the list that you pass it as a side effect. If that's how you intended the function to work, it wouldn't make sense to have a default argument. Nor would it make sense to return the updated list. Without a default argument, the problem goes away.

    If the intent was to return a new list, you need to make a copy of the input list. Python prefers that things be explicit, so it's up to you to make the copy.

    def better_append(new_item, a_list=[]): 
        new_list = list(a_list)
        new_list.append(new_item) 
        return new_list 
    

    For something a little different, you can make a generator that can take a list or a generator as input:

    def generator_append(new_item, a_list=[]):
        for x in a_list:
            yield x
        yield new_item
    

    I think you're under the misconception that Python treats mutable and immutable default arguments differently; that's simply not true. Rather, the immutability of the argument makes you change your code in a subtle way to do the right thing automatically. Take your example and make it apply to a string rather than a list:

    def string_append(new_item, a_string=''):
        a_string = a_string + new_item
        return a_string
    

    This code doesn't change the passed string - it can't, because strings are immutable. It creates a new string, and assigns a_string to that new string. The default argument can be used over and over again because it doesn't change, you made a copy of it at the start.

    0 讨论(0)
提交回复
热议问题