add_digits2(1)(3)(5)(6)(0) should add up all the numbers and stop when it reaches 0.
The output should be 15
The below code works but uses a global variable.
total = 0
def add_digits2(num):
global total
if num == 0:
print(total)
else:
total += num
return add_digits2
The result is correct but needs to do the same thing without using the global variable.
One thing you could do is use partial:
from functools import partial
def add_digits2(num, total=0):
if num == 0:
print(total)
return
else:
total += num
return partial(add_digits2, total=total)
add_digits2(2)(4)(0)
You can just pass in *args as a parameter and return the sum
def add_digits2(*args):
return sum(args)
add_digits2(1, 3, 5 ,6)
You could also use a class, using the __call__ method to obtain this behavior:
class Add_digits:
def __init__(self):
self.total = 0
def __call__(self, val):
if val != 0:
self.total += val
return self
else:
print(self.total)
self.total = 0
add_digits = Add_digits()
add_digits(4)(4)(0)
# 8
add_digits(4)(6)(0)
# 10
though I still don't get why you would want to do this...
Really hard to say what they are after when asking questions like that but the total could be stored in a function attribute. Something like this
>>> def f():
... f.a = 3
>>> f()
>>> f.a
3
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]
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.
I would like to define an Integer class in python, where an Integer (called y) can be related to another Integer (called x) and get updated automatically when this Integer x changes. More concretely I would like to have the following behavior
>>> x = Integer(7)
>>> y = x + 2
>>> print y
9
>>> x.set(9)
>>> print y
11
>>> z = x + y
>>> y.set(10)
>>> print z
19
I realize that one can do this in sympy but I am interested in implementing this myself. I would be grateful if someone can please point out how one would go about this in the simplest manner? Thank you.
I've not used Sympy before but here's my attempt:
class Integer(object):
def __init__(self, value_or_callback):
if isinstance(value_or_callback, int):
self._value_callback = lambda: value_or_callback
else:
self._value_callback = value_or_callback
#property
def value(self):
return self._value_callback()
def set(self, new_value):
self._value_callback = lambda: new_value
def __add__(self, other):
if isinstance(other, int):
return Integer(lambda: self.value + other)
elif isinstance(other, Integer):
return Integer(lambda: self.value + other.value)
else:
raise TypeError(other)
def __radd__(self, other):
return self.__add__(other)
def __repr__(self):
return str(self.value)
if __name__ == '__main__':
x = Integer(7)
y = x + 2
print(y)
x.set(9)
print(y)
z = x + y
y.set(10)
print(z)
Output
9
11
19
Is there anyway to make a python list iterator to go backwards?
Basically i have this
class IterTest(object):
def __init__(self, data):
self.data = data
self.__iter = None
def all(self):
self.__iter = iter(self.data)
for each in self.__iter:
mtd = getattr(self, type(each).__name__)
mtd(each)
def str(self, item):
print item
next = self.__iter.next()
while isinstance(next, int):
print next
next = self.__iter.next()
def int(self, item):
print "Crap i skipped C"
if __name__ == '__main__':
test = IterTest(['a', 1, 2,3,'c', 17])
test.all()
Running this code results in the output:
a
1
2
3
Crap i skipped C
I know why it gives me the output, however is there a way i can step backwards in the str() method, by one step?
EDIT
Okay maybe to make this more clear. I don't want to do a full reverse, basically what i want to know if there is an easy way to do the equivalent of a bidirectional iterator in python?
No, in general you cannot make a Python iterator go backwards. However, if you only want to step back once, you can try something like this:
def str(self, item):
print item
prev, current = None, self.__iter.next()
while isinstance(current, int):
print current
prev, current = current, self.__iter.next()
You can then access the previous element any time in prev.
If you really need a bidirectional iterator, you can implement one yourself, but it's likely to introduce even more overhead than the solution above:
class bidirectional_iterator(object):
def __init__(self, collection):
self.collection = collection
self.index = 0
def next(self):
try:
result = self.collection[self.index]
self.index += 1
except IndexError:
raise StopIteration
return result
def prev(self):
self.index -= 1
if self.index < 0:
raise StopIteration
return self.collection[self.index]
def __iter__(self):
return self
Am I missing something or couldn't you use the technique described in the Iterator section in the Python tutorial?
>>> class reverse_iterator:
... def __init__(self, collection):
... self.data = collection
... self.index = len(self.data)
... def __iter__(self):
... return self
... def next(self):
... if self.index == 0:
... raise StopIteration
... self.index = self.index - 1
... return self.data[self.index]
...
>>> for each in reverse_iterator(['a', 1, 2, 3, 'c', 17]):
... print each
...
17
c
3
2
1
a
I know that this doesn't walk the iterator backwards, but I'm pretty sure that there is no way to do that in general. Instead, write an iterator that walks a discrete collection in reverse order.
Edit you can also use the reversed() function to get a reversed iterator for any collection so that you don't have to write your own:
>>> it = reversed(['a', 1, 2, 3, 'c', 17])
>>> type(it)
<type 'listreverseiterator'>
>>> for each in it:
... print each
...
17
c
3
2
1
a
An iterator is by definition an object with the next() method -- no mention of prev() whatsoever. Thus, you either have to cache your results so you can revisit them or reimplement your iterator so it returns results in the sequence you want them to be.
Based on your question, it sounds like you want something like this:
class buffered:
def __init__(self,it):
self.it = iter(it)
self.buf = []
def __iter__(self): return self
def __next__(self):
if self.buf:
return self.buf.pop()
return next(self.it)
def push(self,item): self.buf.append(item)
if __name__=="__main__":
b = buffered([0,1,2,3,4,5,6,7])
print(next(b)) # 0
print(next(b)) # 1
b.push(42)
print(next(b)) # 42
print(next(b)) # 2
You can enable an iterator to move backwards by following code.
class EnableBackwardIterator:
def __init__(self, iterator):
self.iterator = iterator
self.history = [None, ]
self.i = 0
def next(self):
self.i += 1
if self.i < len(self.history):
return self.history[self.i]
else:
elem = next(self.iterator)
self.history.append(elem)
return elem
def prev(self):
self.i -= 1
if self.i == 0:
raise StopIteration
else:
return self.history[self.i]
Usage:
>>> prev = lambda obj: obj.prev() # A syntactic sugar.
>>>
>>> a = EnableBackwardIterator(iter([1,2,3,4,5,6]))
>>>
>>> next(a)
1
>>> next(a)
2
>>> a.next() # The same as `next(a)`.
3
>>> prev(a)
2
>>> a.prev() # The same as `prev(a)`.
1
>>> next(a)
2
>>> next(a)
3
>>> next(a)
4
>>> next(a)
5
>>> next(a)
6
>>> prev(a)
5
>>> prev(a)
4
>>> next(a)
5
>>> next(a)
6
>>> next(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
You can wrap your iterator in an iterator helper to enable it to go backward. It will store the iterated values in a collection and reuse them when going backwards.
class MemoryIterator:
def __init__(self, iterator : Iterator):
self._iterator : Iterator = iterator
self._array = []
self._isComplete = False
self._pointer = 0
def __next__(self):
if self._isComplete or self._pointer < len(self._array):
if self._isComplete and self._pointer >= len(self._array):
raise StopIteration
value = self._array[self._pointer]
self._pointer = self._pointer + 1
return value
try:
value = next(self._iterator)
self._pointer = self._pointer + 1
self._array.append(value)
return value
except StopIteration:
self._isComplete = True
def prev(self):
if self._pointer - 2 < 0:
raise StopIteration
self._pointer = self._pointer - 1
return self._array[self._pointer - 1]
The usage can be similar to this one:
my_iter = iter(my_iterable_source)
memory_iterator = MemoryIterator(my_iter)
try:
if forward:
print(next(memory_iterator))
else:
print(memory_iterator.prev())
except StopIteration:
pass
I came here looking for a bi-directional iterator. Not sure if this is what the OP was looking for but it is one way to make a bi-directional iterator—by giving it an attribute to indicate which direction to go in next:
class BidirectionalCounter:
"""An iterator that can count in two directions (up
and down).
"""
def __init__(self, start):
self.forward = True
# Code to initialize the sequence
self.x = start
def __iter__(self):
return self
def __next__(self):
if self.forward:
return self.next()
else:
return self.prev()
def reverse(self):
self.forward = not self.forward
def next(self):
"""Compute and return next value in sequence.
"""
# Code to go forward
self.x += 1
return self.x
def prev(self):
"""Compute and return previous value in sequence.
"""
# Code to go backward
self.x -= 1
return self.x
Demo:
my_counter = BidirectionalCounter(10)
print(next(my_counter))
print(next(my_counter))
my_counter.reverse()
print(next(my_counter))
print(next(my_counter))
Output:
11
12
11
10
i think thi will help you to solve your problem
class TestIterator():
def __init__(self):`
self.data = ["MyData", "is", "here","done"]
self.index = -1
#self.index=len(self.data)-1
def __iter__(self):
return self
def next(self):
self.index += 1
if self.index >= len(self.data):
raise StopIteration
return self.data[self.index]
def __reversed__(self):
self.index = -1
if self.index >= len(self.data):
raise StopIteration
return self.data[self.index]
r = TestIterator()
itr=iter(r)
print (next(itr))
print (reversed(itr))
ls = [' a', 5, ' d', 7, 'bc',9, ' c', 17, '43', 55, 'ab',22, 'ac']
direct = -1
l = ls[::direct]
for el in l:
print el
Where direct is -1 for reverse or 1 for ordinary.
Python you can use a list and indexing to simulate an iterator:
a = [1,2,3]
current = 1
def get_next(a):
current = a[a.index(current)+1%len(a)]
return current
def get_last(a):
current = a[a.index(current)-1]
return current # a[-1] >>> 3 (negative safe)
if your list contains duplicates then you would have to track your index separately:
a =[1,2,3]
index = 0
def get_next(a):
index = index+1 % len(a)
current = a[index]
return current
def get_last(a):
index = index-1 % len(a)
current = a[index-1]
return current # a[-1] >>> 3 (negative safe)
An iterator that visits the elements of a list in reverse order:
class ReverseIterator:
def __init__(self,ls):
self.ls=ls
self.index=len(ls)-1
def __iter__(self):
return self
def __next__(self):
if self.index<0:
raise StopIteration
result = self.ls[self.index]
self.index -= 1
return result
I edited the python code from dilshad (thank you) and used the following Python 3 based code to step between list item's back and forth or let say bidirectional:
# bidirectional class
class bidirectional_iterator:
def __init__(self):
self.data = ["MyData", "is", "here", "done"]
self.index = -1
def __iter__(self):
return self
def __next__(self):
self.index += 1
if self.index >= len(self.data):
raise StopIteration
return self.data[self.index]
def __reversed__(self):
self.index -= 1
if self.index == -1:
raise StopIteration
return self.data[self.index]
Example:
>>> r = bidirectional_iterator()
>>> itr=iter(r)
>>> print (next(itr))
MyData
>>> print (next(itr))
is
>>> print (next(itr))
here
>>> print (reversed(itr))
is
>>> print (reversed(itr))
MyData
>>> print (next(itr))
is
This is a common situation when we need to make an iterator go back one step. Because we should get the item and then check if we should break the loop. When breaking the loop, the last item may be requied in later usage.
Except of implementing an iteration class, here is a handy way make use of builtin itertools.chain :
from itertools import chain
>>> iterator = iter(range(10))
>>> for i in iterator:
... if i <= 5:
... print(i)
... else:
... iterator = chain([i], iterator) # push last value back
... break
...
0
1
2
3
4
5
>>> for i in iterator:
... print(i)
...
6
7
8
9
please see this function made by Morten Piibeleht. It yields a (previous, current, next) tuple for every element of an iterable.
https://gist.github.com/mortenpi/9604377