Hello I have these two classes
class BaseCounter(object):
def __init__(self):
print ("BaseCounter init = ")
self._counter = 0
def increment(self, count=1):
self._counter += count
def items(self):
return self._counter
class DictCounter(object):
def __init__(self, dict_class):
self._counter = defaultdict(lambda: dict_class)
def increment(self, key, value, *args, **kwargs):
print (key, value, args, kwargs)
self._counter[key].increment(value, *args, **kwargs)
def items(self):
result = []
for key, counter in self._counter.items():
result.append((key, counter.items()))
return result
and I am trying to create something like this:
y = DictCounter(DictCounter(DictCounter(BaseCounter())))
y.increment(10,1,2,3)
y.increment(10,1,2,3)
y.increment(10,1,3,3)
y.increment(10,2,2,3)
which leads to
10 1 2 12
10 1 3 12
10 2 2 12
10 2 3 12
but I was expecting
10 1 2 6
10 1 3 3
10 2 2 3
it should simulate, which is working correctly
defaultdict(defaultdict(defaultdict(int))) "with counter at the end"
but I am confused with the behavior (I think there will be problem with shallow copy or something with references)
Any idea?
As Martijn Pieters said. The problem was referencing to the same object (dict_class) for every new key. So instead of this:
class DictCounter(object):
def __init__(self, dict_class):
self._counter = defaultdict(lambda: dict_class)
....
DictCounter(DictCounter(DictCounter(BaseCounter())))
do this:
class DictCounter(object):
def __init__(self, dict_class):
self._counter = defaultdict(dict_class)
....
DictCounter(lambda: DictCounter(lambda: DictCounter(lambda: BaseCounter())))
I was trying to describe it a little bit more at my blog.
Related
I am trying to create a "CumulativeMovingAverage" class. That's what I did:
class CumulativeMovingAverage():
cma = None
n = 0
def add(self, *args):
if self.cma is None:
self.cma = args[0]
else:
self.cma = (args[0] + self.n*self.cma) / (self.n+1)
self.n += 1
return None
def __call__(self):
return self.cma
It works like this:
a = CumulativeMovingAverage()
a.add(2)
a.add(4)
a.cma ==> 3
a() ==> 3
I would like to overwrite a dunder method such that
a ==> 3
and also
b = a + 100
b ==> 103
That is, without having to call a with parenthesis. Is it possible? What dunder should I overwrite?
I am trying to create a class MarblesBoard also include switch and rotate function.
My code is below:
class MarblesBoard():
def __init__(self, balls):
self.balls = balls
def __repr__(self):
return " ".join(str(i) for i in self.balls)
def switch(self):
lst=list(self.balls)
lst[0], lst[1] = lst[1], lst[0]
return lst
def rotate(self):
lst=list(self.balls)
lst = lst[1:]+lst[:1]
return self.balls
The out put should be like:
>>> board = MarblesBoard((3,6,7,4,1,0,8,2,5))
>>> board
3 6 7 4 1 0 8 2 5
>>> board.switch()
>>> board
6 3 7 4 1 0 8 2 5
>>> board.rotate()
>>> board
3 7 4 1 0 8 2 5 6
>>> board.switch()
>>> board
7 3 4 1 0 8 2 5 6
However, when I use switch or rotate, it allays call the original ball list. Not sure how to solve this.
You aren't actually modifying self.balls, just returning a modified list.
If you want to keep your methods basically the same, and continue to work with tuples, you could change the definition of switch() to actually write the changes to self.balls by doing something like:
def switch(self):
lst=list(self.balls)
lst[0], lst[1] = lst[1], lst[0]
self.balls = tuple(lst)
Likewise, you can change rotate() to something like this:
def rotate(self):
lst=list(self.balls)
lst = lst[1:]+lst[:1]
self.balls=tuple(lst)
Your methods are returning lists. If you want to modify the object, you have to change self.balls instead of returning. Like this:
class MarblesBoard:
def __init__(self, balls):
self.balls = balls
def __repr__(self):
return " ".join(str(i) for i in self.balls)
def switch(self):
self.balls[0], self.balls[1] = self.balls[1], self.balls[0]
def rotate(self):
self.balls = self.balls[1:] + self.balls[:1]
This is my code that I wanted to create,
class RegularPolygon :
def __init__(self):
self.__n =3
self.__side = 1
self.__x = 0
self.__y = 0
def get_n(self):
return self.__n
def get_side(self):
return self.__side
def getX(self):
return self.__x
def getY(self):
return self.__y
So If I run the below code to check,
polygon1 = RegularPolygon()
print(polygon1.get_n(), polygon1.get_side(), polygon1.getX(), polygon1.getY() )
It gives me 3 0 1 1 as result.
but I'd like to make a change that when I put order like
polygon2 = RegularPolygon(6)
print(polygon2.get_n(), polygon2.get_side(), polygon2.getX(), polygon2.getY() )
I want to have 6 0 1 1 for my result.
So my question is, how can I still get 3 0 1 1 when I don't put any argument in running RegularPolygon() but If put any integer such as 6, it gives me 6?
as user2896976 said just change
def __init__(self):
self.__n =3
to
def __init__(self, n=3):
self.n = n
This will mean n by default is set to 3 when you do not specify it, but when u specifiy it, like when u enter 6, it also gives that output too.
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?
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.
__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.
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, 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
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
I am recursively generating few objects, which need a contiguous, unique id. How can I guarantee (easiest) the synchronization in python 2.7.
iid = 1
def next_id():
iid += 1
return iid
def process():
# .. do something
id = next_id()
from itertools import count
iid = count()
print next(iid) # 0
print next(iid) # 1
print next(iid) # 2
etc., and
new_iid = count(10)
print next(new_iid) # 10
print next(new_iid) # 11
print next(new_iid) # 12
for starting at other values than 0.
count() is essentially a generator which infinitely yields values.
Use a mutex:
import threading
iid = 1
iid_lock = threading.Lock()
def next_id():
global iid
with iid_lock:
result = iid
iid += 1
return result
You might like to hide the internals in a class:
class IdGenerator(object):
def __init__(self):
self.cur_id = 1
self.lock = threading.Lock()
def next_id(self):
with self.lock:
result = self.cur_id
self.cur_id += 1
return result
EDIT: Based on the comments, it seems like you're not using threads. This means you don't need the locking mechanism at all. What you initially wrote would be sufficient, though you need the global keyword to make the global variable mutable:
iid = 1
def next_id():
global iid
res = iid
iid += 1
return res
You were thinking to something of this kind:
class Counter():
def __init__(self):
self.theCount = -1
def __call__(self):
self.theCount += 1
return self.theCount
class BorgCounter():
Borg = {'theCount':-1}
def __init__(self):
self.__dict__ = BorgCounter.Borg
def __call__(self):
self.theCount += 1
return self.theCount
myCount = Counter()
mycount2 = Counter()
assert(myCount()==0)
assert(mycount2()==0)
assert(mycount2()==1)
assert(myCount()==1)
assert(myCount()==2)
myCount = BorgCounter()
mycount2 = BorgCounter()
assert(myCount()==0)
assert(mycount2()==1)
assert(mycount2()==2)
assert(myCount()==3)
assert(myCount()==4)