how can i iterate class objects while using generator in python? - python-3.x

i want to compare the 2000 pairs of a and b, and print the matching pairs and count of them.can anyone help me to get rid of it.it shows this error TypeError: 'seq_generator' object is not iterable at line 34
class generator(object):
def __init__(self,s,start_A,fact_A):
self.s=s
self.start_A=start_A
self.fact_A = fact_A
def seq_gen_A(self):
while self.s>0:
self.gen_A=(self.start_A*self.fact_A)%2147483647
self.g=self.gen_A
self.start_A=self.gen_A
self.bin_A=(bin(self.gen_A)[-16:])
yield self.bin_A
self.s=self.s-1
def next(self):
for i in self.seq_gen_A():
return i
def main():
s=200
count=0
a=generator(s,65,16807)
b=generator(s,8921,48271)
print("Matching pair")
print("*************")
for i in range(0,s):
if next(a)==next(b):
count+=1
print(a,b)
print('Matching pair count',count)

You are defining your generator not correctly. You need methods __iter__ and __next__:
class generator(object):
def __init__(self, s, start_A, fact_A):
self.s = s
self.start_A = start_A
self.fact_A = fact_A
def __iter__(self):
return self
def __next__(self):
if self.s <= 0:
raise StopIteration()
gen_A = (self.start_A*self.fact_A)%2147483647
self.start_A = gen_A
yield bin(gen_A)[-16:]
self.s -= 1

Related

Python Class, Operator Overloading

Recently while getting my hands on with Python Class concepts, I came upon this observation and was not able to understand.
When I try and create instance out of the below class interactively(Python console), I also get the Finding __len__ line in output.
class MyClass(object):
counter = 0
data = 'Class Variable'
def __init__(self):
self.counter += 1
self.value = -1
def __str__(self):
return "Instance {} is the {} instance".format(self.__class__.__name__, self.counter)
def __getattr__(self, item):
print(f'Finding {item}')
return self.__dict__.get(item, f'Attr {item} not available, {self.__dict__}')
def __setattr__(self, key, value):
if key not in self.__dict__:
self.__dict__[key] = value
def __delattr__(self, item):
print(f'Deleting attr: {item}')
if item in self.__dict__:
del self.__dict__[item]
else:
print(f'Cannot find {item} in {self.__dict__}')
if __name__ == '__main__':
inst = MyClass()
print(inst.id)
But running it as a top level module, doesn't add this additional line in output.
Can someone help me understand, why Finding __len__ output would be displayed interactively.
Below is an interactive output,
import WS1
x = WS1.MyClass()
Finding __len__
x.name = 'Yathin'
Finding __len__

Why generator object is not return generator?

I have simple iteration object that use generator. But __iter__() method of Obj() can not get iterator from Generator().__init__()
Live demo is here.
#!/usr/bin/env python3
class Obj():
def __init__(self, word):
self.word = word
def __iter__(self):
return Generator(self.word)
class Generator():
def __init__(self, word):
for l in word:
yield l
obj = Obj('qwe')
it = iter(obj)
print(it.__next__())
print(it.__next__())
print(it.__next__())
I expect console output to be 'qwe'.
__init__ cannot return or yield a non-None value. With what you have, Generator is not a generator object, but Obj is. Obj.__iter__ is the method that should be yielding values, and you can probably get rid of the Generator class altogether, unless it is used for other things that you haven't shown in your posted snippet.
class Obj():
def __init__(self, word):
self.word = word
def __iter__(self):
for l in self.word:yield l
obj = Obj('qwe')
print(obj.__next__())
print(obj.__next__())
print(obj.__next__())

How to implement a iterator or generator for my Delegate class?

I implemented a Delegate class in Python 3, which wraps a function object in a object instance. It's possible to register multiple function objects on one delegate (in .NET terminology it's a MultiCastDelegate). Assumed all registered functions accept the same parameters, it's possible to invoke the delegate and call all functions at once.
Delegate implementation:
class Delegate:
def __init__(self, *funcs):
self.__invocationList__ = []
for func in funcs:
self.__invocationList__.append(func)
def __iadd__(self, func):
self.__invocationList__.append(func)
return self
def __isub__(self, func):
self.__invocationList__.remove(func)
return self
def __call__(self, *args, **kwargs):
if (len(self.__invocationList__) == 1):
return self.__invocationList__[0](*args, **kwargs)
else:
res = {}
for func in self.__invocationList__:
res[func] = func(*args, **kwargs)
return res
#property
def isMulticast(self):
return (len(self.__invocationList__) > 1)
Usage examples:
def test1():
return 5
def test2(a, b):
return a + b
def test3(a, b):
return a * b + 15
delegate = Delegate(test1)
result = delegate()
print("test1: {0}".format(result))
delegate = Delegate(test2)
result = delegate(3, 8)
print("test2: {0}".format(result))
delegate += test3
results = delegate(2, 9)
print("test2: {0}".format(results[test2]))
print("test3: {0}".format(results[test3]))
I would like to implement an iterator or generator on this class, so it's possible to use the delegate in for loops.
How could it look like?
# loop over every result from delegate, call with parameters 4 and 18
for result in delegate(4, 18):
print("function={0} result={1}".format(*result))
The iterators __next__() method should return a tuple consisting of the function-object and return value.
What I tried so far:
class Delegate:
# ...
# see code from above
def __iter__(self):
print("Delegate.__iter__():")
class iter:
def __init__(self2, *args, **kwargs):
print(str(args))
self2.__args = args
self2.__kwargs = kwargs
self2.__index = 0
def __iter__(self2):
return self2
def __next__(self2):
if (self2.__index == len(self.__invocationList__)):
raise StopIteration
func = self.__invocationList__[self2.__index]
self2.__index += 1
return func(*self2.__args, **self2.__kwargs)
return iter()
Because the constructor method is already in use by the Delegate creation itself, I implemented the iterator as a nested class. But unfortunately, I can not pass the call parameters *args and **kwargs to the iterator.
So my questions:
Is it possible and wise the implement a iterator / generator pattern for delegates?
What should I change to get it working?
I just tried to implement the iterator pattern. If it works, I would like to upgrade it to a generator - if possible :)
I'm not familiar with this, but I gave it a shot. It is not well tested, but it will help you on the way to solve your task. Here is the code:
class Delegate:
class IterDelegate:
def __init__(this, invocationList, *args, **kwargs):
this.__args = args
this.__kwargs = kwargs
this._invocationList = invocationList
def __iter__(this):
this.__index = 0
return this
def __next__(this):
if this.__index < len(this._invocationList):
func = this._invocationList[this.__index]
this.__index += 1
return (func.__name__, func(*this.__args, **this.__kwargs))
raise StopIteration
def __init__(self, func):
if (type(func) == 'list'):
self._invocationList = func
else:
self._invocationList = [func]
def __call__(self, *args, **kwargs):
return self.IterDelegate(self._invocationList, *args, **kwargs)
def __iadd__(self, func):
self._invocationList.append(func)
return self
def __isub__(self, func):
self._invocationList.remove(func)
return self
def test2(a, b):
return a + b
def test1(*args):
return 6
delegate = Delegate(test2)
delegate += test1
results = delegate(2,3)
for r in results:
print("function={0} result={1}".format(*r))
This will give the results
function=test2 result=5
function=test1 result=6

endless container iterator with backward\forward movement support

Is in standart library container with endless forward/backward movement support, like itertools.cycle? Or how to implement one-liner for it?
Current code (github):
def __init__(self, ...):
self.__weapons = [Weapon()("Blaster"), Weapon()("Laser"), Weapon()("UM")]
self.__weapon = self.__weapons[0]
...
def next_weapon(self):
ind = self.__weapons.index(self.__weapon)
if ind < len(self.__weapons) - 1:
self.__weapon = self.__weapons[ind+1]
else:
self.__weapon = self.__weapons[0]
And almost the same code for prev_weapon method.
I want to iterate on endless container in both directions=)
Thanks in advance,
Paul
I decided that best solution is to extend List.
class InfList(list):
"""Infinite list container"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._index = 0
def current(self):
return self[self._index]
def next(self):
self._index = (self._index + 1) % len(self)
return self[self._index]
def prev(self):
self._index = (self._index - 1) % len(self)
return self[self._index]

Python Binary Tree

I'm working on a binary tree in Python3 and so far almost everything has been working like expected; however, I have a function that is supposed to return a list of all children for any given node and for whatever reason I'm only getting a list of the object addresses, and not calling my overridden __str__(self) method.
from collections import deque # http://docs.python.org/3.1/tutorial/datastructures.html
class BinaryNode: # binary tree functionality via iterative means
def __init__(self, name, data):
self.Left = None
self.Right = None
self.Parent = None
self.Name = name
self.Data = data
return
def AddNew(self, name, data):
q = []
q.append(self)
while q:
i = q.pop()
if i.Name == name:
i.Data = data
return i
elif name < i.Name:
if i.Left:
q.append(i.Left)
else:
i.Left = BinaryNode(name, data)
i.Left.Parent = i
return i.Left
else:
if i.Right:
q.append(i.Right)
else:
i.Right = BinaryNode(name, data)
i.Right.Parent = i
return i.Right
def Find(self, name):
q = deque()
q.append(self)
'''if self.Left: q.append(self.Left)
if self.Right: q.append(self.Right)'''
while q:
i = q.pop()
print(i)
if i.Name == name:
return i
elif name < i.Name:
if i.Left: q.append(i.Left)
else: return None
else:
if i.Right: q.append(i.Left)
else: return None
def Children(self):
children = []
q = deque()
if self.Left: q.append(self.Left)
if self.Right: q.append(self.Right)
while q:
i = q.popleft()
if i.Left: q.append(i.Left)
if i.Right: q.append(i.Right)
children.append(i)
return children
def Parents(self):
lst = []
i = self.Parent
while i is not None:
lst.append(i)
i = i.Parent
return lst
def __str__(self): return "{} : {}".format(self.Name, self.Data)
and I'm testing it by calling
test = BinaryNode("Jesse", 21)
print(test)
print(test.AddNew("David", 22))
print(test.AddNew("Marli", 23))
print(str(test.Children()))
print(test.Find("David"))
print(test.Find("David").Children())
print(test.Find("Gary")) #Will return None
with the resulting console output
Jesse : 21
David : 22
Marli : 23
[<__main__.BinaryNode object at 0x000000000333E160>, <__main__.BinaryNode object at 0x000000000333E1D0>, <__main__.BinaryNode object at 0x000000000333E198>]
David : 22
[<__main__.BinaryNode object at 0x000000000333E1D0>]
None
UPDATE:
Here is the answer I implemented:
def __repr__ (self): return str(self)
Python containers always use the representation of contained objects.
Implement a __repr__ method too and that'll be used when printing the list; you can make it an alias for __str__ if you wish:
__repr__ = __str__
or explicitly print each element in your list:
print(', '.join(map(str, test.Children())))

Resources