2015-03-24 3 views
1

Я пытаюсь выяснить, как изменить значение после каждого вызова объекта. Я хочу, чтобы вызывал функцию() после каждого вызова.Изменить атрибут после каждого вызова объекта

Это должен быть простой класс счетчика, который уменьшает атрибут value после его вызова.

class counter(): 
    def __init__(self,value): 
     self.value = value 

    def __call__(self): 
     self.value -= 1 

count = counter(50) 
print count.value 
print count.value 

>> 50 
>> 50 <-- this should be 49 

Что я делаю неправильно?

+0

[ '__call__' ] (https://docs.python.org/2/reference/datamodel.html#object.__call__) вызывается, когда вы вызываете свой экземпляр как функция. т.е. после выполнения 'count()', 'count.value' будет 49. Возможно, вы ищете [' __getattribute__'] (https://docs.python.org/2/reference/datamodel.html#object.__getattribute__) – Matt

+0

@Matt: Я пытался использовать __getattribute__, но все тот же. Вы можете мне помочь? Спасибо –

+0

Вы хотите, чтобы count.value уменьшалось на 1 при каждом обращении? – Matt

ответ

3

Если вы не стремится к классам вам, может использовать функцию и злоупотребления с использованием изменяемых-типов-как-по-умолчанию, инициализаторами:

def counter(init=None, container=[0]): 
    container[0] -= 1 
    if init is not None: container[0] = init 
    return container[0] 


x = counter(100) 
print(x) # 100 
print(counter()) # 99 
print(counter()) # 98 
print(counter()) # 97 
# ... 

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

Звоните counter без аргументов, чтобы получить «следующее значение».

(Очень похоже на то, что я предложил here)

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

class Counter(object): 
    def __init__(self, init): 
     self.val = init 

    @property 
    def value(self): 
     val = self.val 
     self.val -= 1 
     return val 

count = Counter(50) 

print(count.value) # 50 
print(count.value) # 49 
print(count.value) # 48 
print(count.value) # 47 
#... 

Здесь вы создаете объект Countercount, то каждый раз, когда вы вызываете count.value, он возвращает текущее значение и готовится к будущему вызову, уменьшая его внутренний атрибут val.

Снова при первом запросе атрибута value он возвращает номер, с которого вы его инициализировали.

Если по какой-то причине вы хотите «заглянуть» на то, что будет следующим вызовом count.value, без декремента, вы можете посмотреть на count.val.

+0

Вы должны заглянуть в [закрытия] (http://en.wikipedia.org/wiki/Closure_%28computer_programming%29). Это в основном то, что вы делаете, используя '[]' в качестве аргумента по умолчанию, но вместо этого используйте закрытие, вы можете использовать функцию счетчика для создания нескольких счетчиков. Взгляните на мой [ответ] (http://stackoverflow.com/a/29244937/4687645) – Matt

3

__call__ вызывается только при вызове объекта с помощью ()

Чтобы вызвать это поведение, которое вы должны были бы сделать

class counter(): 
    def __init__(self,value): 
     self.value = value 

    def __call__(self): 
     print 'called' 
     self.value -= 1 

count = counter(50) 
print count.value 
count() 
print count.value 

Это не может быть именно то, что вы хотите сделать.

0

Определение настраиваемого метода вызов метода() в метаклассе допускает настраиваемое поведение при вызове класса, например. не всегда создает новый instance.As не новый экземпляр класса не создается вызов вызывается вместо инициализации .so сделать это, чтобы получить желаемый результат

print count.value 
count() 
print count.value 
1

Use the property decorator

class counter: 
    def __init__(self, value): 
     self._value = value + 1 

    @property 
    def value(self): 
     self._value -= 1 
     return self._value 

count = Counter(50) 
print(count.value) # 50 
print(count.value) # 49 

Alternatly, вы могли бы использовать closure:

def Counter(n): 
    n += 1 
    def inner(): 
     n -= 1 
     return n 
    return inner 

Хотя это должно быть названо каждый раз, когда вы хотите использовать его

count1 = Counter(50) 
count2 = Counter(50) 
print(count1()) # 50 
print(count1()) # 49 
print(count2()) # 50 
print(count2()) # 49 
print(count1()) # 48 
Смежные вопросы