Что такое pythonic, чтобы избежать параметров по умолчанию, которые являются пустыми списками?

Иногда кажется естественным, что параметр по умолчанию является пустым. Однако Python дает неожиданное поведение в этих ситуациях.

Если, например, у меня есть функция:

def myFunc(working_list = []): working_list.append("a") print working_list 

При первом вызове с по умолчанию будет работать, но вызовы после этого будут использовать постоянно обновляемый список.

Итак, что такое питонический способ получить желаемое поведение (новый список для каждого вызова)?

  • Как получить полный список методов и атрибутов объекта?
  • Как перебирать файл в python
  • Почему в Python иногда из импорта PIL изображение выходит из строя и импортируется Image?
  • Как повторно импортировать обновленный пакет в Python Interpreter?
  • Как вызвать тот же метод для списка объектов?
  • ForbiddenError при попытке записать файл в GCS из приложения GAE python
  • python 2 и python 3 __cmp__
  • Самые длинные строки из списка
  • 6 Solutions collect form web for “Что такое pythonic, чтобы избежать параметров по умолчанию, которые являются пустыми списками?”

     def myFunc(working_list=None): if working_list is None: working_list = [] working_list.append("a") print working_list 

    как я это делаю.

    Не то, чтобы это имело значение в этом случае, но вы можете использовать идентификатор объекта для проверки на None:

     if working_list is None: working_list = [] 

    Вы также можете воспользоваться тем, как булевой оператор или определяется в python:

     working_list = working_list or [] 

    Хотя это будет вести себя неожиданно, если вызывающий абонент предоставит вам пустой список (который считается как false) в качестве рабочего_каталога и ожидает, что ваша функция изменит список, который он ему дал.

    Если целью функции является изменение параметра, переданного как рабочий список, см. Ответ HenryR (= None, проверка на отсутствие внутри).

    Но если вы не собираетесь мутировать аргумент, просто используйте его как отправную точку для списка, вы можете просто скопировать его:

     def myFunc(starting_list = []): starting_list = list(starting_list) starting_list.append("a") print starting_list 

    (или в этом простом случае просто print starting_list + ["a"] но я думаю, что это был просто игрушечный пример)

    В общем, мутация ваших аргументов – это плохой стиль в Python. Единственными функциями, которые полностью ожидаются для мутирования объекта, являются методы объекта.

    • Если вы делаете это из привычки C для «выходных аргументов», это совершенно не нужно – вы всегда можете возвращать несколько значений в виде кортежа.

    • Если вы сделаете это, чтобы эффективно построить длинный список результатов без создания промежуточных списков, подумайте о том, чтобы записать его как генератор и использовать result_list.extend(myFunc()) когда вы его вызываете. Таким образом, ваши соглашения о звонках остаются очень чистыми.

    Существующие ответы уже предоставили прямые решения по запросу. Однако, поскольку это очень распространенная ошибка для новых программистов на Python, стоит добавить объяснение, почему python ведет себя таким образом, что хорошо описано в « Руководстве автостопом по Python » как « Mutable Default Arguments »: http: // python -guide-pt-br.readthedocs.io/en/latest/writing/gotchas/

    Цитата: « По умолчанию аргументы Python оцениваются один раз, когда функция определена, а не каждый раз, когда функция вызывается (например, это говорит« Руби »). Это означает, что если вы используете изменяемый аргумент по умолчанию и мутируете его, вы будете иметь мутировал этот объект для всех будущих вызовов функции, а также "

    Пример кода для его реализации:

     def foo(element, to=None): if to is None: to = [] to.append(element) return to 

    Я мог бы быть вне темы, но помните, что если вы просто хотите передать переменное количество аргументов, пифонический путь – передать кортеж *args или словарь **kargs . Они являются необязательными и лучше, чем синтаксис myFunc([1, 2, 3]) .

    Если вы хотите передать кортеж:

     def myFunc(arg1, *args): print args w = [] w += args print w >>>myFunc(1, 2, 3, 4, 5, 6, 7) (2, 3, 4, 5, 6, 7) [2, 3, 4, 5, 6, 7] 

    Если вы хотите передать словарь:

     def myFunc(arg1, **kargs): print kargs >>>myFunc(1, option1=2, option2=3) {'option2' : 2, 'option1' : 3} 

    Уже есть хорошие и правильные ответы. Я просто хотел дать еще один синтаксис, чтобы написать то, что вы хотите сделать, что я считаю более красивым, когда вы, например, хотите создать класс с пустыми списками по умолчанию:

     class Node(object): def __init__(self, _id, val, parents=None, children=None): self.id = _id self.val = val self.parents = parents if parents is not None else [] self.children = children if children is not None else [] 

    В этом фрагменте используется синтаксис оператора if else. Мне это особенно нравится, потому что это аккуратный маленький лайнер без двоеточий и т. Д., И он почти читается как обычное английское предложение. 🙂

    В вашем случае вы могли бы написать

     def myFunc(working_list=None): working_list = [] if working_list is None else working_list working_list.append("a") print working_list 
    Python - лучший язык программирования в мире.