Есть ли способ сбросить частичный аргумент python без необходимости переопределения самой частичной функции?

Например, я хотел бы иметь возможность сбросить аккумулятор ниже:

accum = []
def accumulator(list, item):
    list.append(item)

a = partial(accumulator, accum)
a(5)
a(7)
accum

Который печатает [5, 7] как ожидалось. Теперь я хочу сбросить список до пустого, но сохранить заданное поведение a:

accum = []
a(8)
accum

Я ожидаю [8], но на этот раз я получаю пустой список. Есть ли способ сохранить связь между определенной функцией и переменной во внешней области видимости?

1
Allen Wang 28 Авг 2017 в 23:35

3 ответа

Лучший ответ

partial связывает объекты, а не переменные; a имеет ссылку на объект списка, на который ссылается accum, а не ссылку на переменную accum. Присвоение accum приведет только к повторной привязке ссылки accum, а не ссылки на объект partial.

Пока вы можете очистить список объектов:

accum.clear()

Или до Python 3.3:

del accum[:]

Вся эта установка с изменяемым объектом, связанным с partial, выглядит как рецепт для странных ошибок псевдонимов и отслеживания состояния. Я бы порекомендовал другой подход к любой проблеме, которую вы пытаетесь решить.

6
user2357112 supports Monica 28 Авг 2017 в 20:38

Python создает замыкание, что означает, что частичное возвращает функцию a, которая содержит указатель на список accum, скажем, 0x1 в памяти.

Теперь вы создаете новый список в 0x2 и заменяете указатель в переменной аккумулятора. функция все еще смотрит на 0x1.

Вы можете использовать

accum.clear() 

Который даст вам желаемое поведение.

1
Eytan 28 Авг 2017 в 20:40

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

def accumulator():
    acc = [] #each time you call accumulator, you have a new list
    def inner(item):
        acc.append(item) #that list is shared on each call of the returned inner
        return acc
    return inner

foo = accumulator()

print(foo(2))
print(foo(3))
print(foo(4))

bar = accumulator()
print(bar(9))
0
Solaxun 28 Авг 2017 в 21:00