Reputation: 18725
I'm trying to figure out how to change some value after each call of the object. I thougt that call() function is executed after each call.
This should be a simple counter class which decreases value attribute after being called.
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
What am I doing wrong?
Upvotes: 2
Views: 311
Reputation: 744
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, you could use a closure:
def Counter(n):
n += 1
def inner():
n -= 1
return n
return inner
Though this has to be called every time you want to use it
count1 = Counter(50)
count2 = Counter(50)
print(count1()) # 50
print(count1()) # 49
print(count2()) # 50
print(count2()) # 49
print(count1()) # 48
Upvotes: 2
Reputation: 30210
If you're not committed to classes, you could use a function and abuse using mutable-types-as-default-initializers:
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
# ...
Call counter
with a single argument to set/initialize the counter. Since initialization is actually the first call to the function, it will return that number.
Call counter
with no arguments to get the "next value".
(Very similar to what I suggested here)
Alternatively, for a syntax closer to what you had in your question, use 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
#...
Here, you're creating a Counter
object called count
, then every time you call count.value
it returns the current value and prepares itself for a future call by decrementing it's internal val
attribute.
Again, the first time you request the value
attribute, it returns the number you initialized it with.
If, for some reason, you want to "peek" at what the next call to count.value
will be, without decrementing it, you can look at count.val
instead.
Upvotes: 3
Reputation: 1381
Defining a custom call() method in the meta-class allows custom behaviour when the class is called, e.g. not always creating a new instance.As no new class instance is created call gets called instead of init.So do this to get the desired result
print count.value
count()
print count.value
Upvotes: 0
Reputation: 21609
__call__
is only invoked when you call the object using ()
To invoke this behaviour you'd have to do
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
This may not be exactly what you wanted to do.
Upvotes: 3