What exactly is not iterable here, and how to fix it? - python

This kind of questions has been asked a lot here, but I still don't know why it happens here. The error massage is:
TypeError: 'P' object is not iterable
and is invoked by for p in self.parents: from __str__
Why P isn't iterable?
class P:
limit = 8
def __init__(self,x=0,y=0,p=None):
self.x = x
self.y = y
self.parents = p
def __str__(self):
s = ''
for p in self.parents:
s += '({},{}->)'.format(p.x,p.y)
s += '({},{}->)'.format(self.x,self.y)
return s + '\n'
def next_move(self):
def valid(x):
return x >= 0 and x < P.limit
x,y = self.x,self.y
a = [-1,1]
b = [-2,2]
ls = [(x+i, y+j) for i in a for j in b if valid(x+i) and valid(y+j)]
ls +=[(x+i, y+j) for i in b for j in a if valid(x+i) and valid(y+j)]
to_return = []
for i in range(len(ls)):
to_return += P(ls[i][0],ls[i][1],self)
return to_return
p = P()
print (p.next_move())
EDIT:
My issue here is not how to remove the error (using append) but how to use next_move() to create a list of new P that are a horse-move (Chess) away from the parent, and also append said parent to the parents attribute in the new object. The answers you gave me help avoid the error, but I don't know how to proceed

Two issues:
Firstly, You are trying to add a P instance to a list via +=. But += for lists roughly corresponds to extend and takes an iterable:
for i in range(len(ls)):
to_return += [P(...)]
# OR
# to_return.append(P(...))
Secondly, when you call the constructor with P(ls[i][0], ls[i][1], self), you are passing self as the p parameter which should be iterable itself. You might want to use P(ls[i][0], ls[i][1], [self]) instead.

You are actually getting this error at the following line:
to_return += P(ls[i][0],ls[i][1],self)
This is because you should be appending to to_return like this
to_return.append(P(ls[i][0],ls[i][1],self))
or, if you have any particular reasons to do so, like this:
to_return += [P(ls[i][0],ls[i][1],self)]
In addition, that self you passed as argument is not iterable either. Then you would have the problem in __str__, if it was to be called.
to_return.append(P(ls[i][0], ls[i][1], [self]))
Finally, I believe you meant __repr__ instead of __str__, so that you print:
[(0,0->)(1,2->)
, (0,0->)(2,1->)
]

Try this:
class P:
limit = 8
def __init__(self, x=0, y=0, p=None):
self.x = x
self.y = y
self.parents = p
def __str__(self):
s = ''
for p in self.parents:
s += '({},{}->)'.format(p.x, p.y)
s += '({},{}->)'.format(self.x, self.y)
return s + '\n'
def next_move(self):
def valid(x):
return 0 <= x < P.limit
x, y = self.x, self.y
a = [-1, 1]
b = [-2, 2]
ls = [(x + i, y + j) for i in a for j in b if valid(x + i) and valid(y + j)]
ls += [(x + i, y + j) for i in b for j in a if valid(x + i) and valid(y + j)]
to_return = []
for i in range(len(ls)):
to_return.append(P(ls[i][0], ls[i][1], self))
return to_return
p = P()
print(p.next_move())
See changes in Line 27
Because to_return is a list, so we can't use + operator. We can use append function for list.

Related

How can I use an element of a python array that is an instance of an object in a function by using the index into the array?

I have a task wherein I am to determine if a Point(x,y) is closer than some amount to any of the Points that are stored in a Python array. Here is the test code:
from point import *
collection = []
p1 = Point(3,4)
collection.append(p1)
print(collection)
p2 = Point(3,0)
collection.append(p2)
print(collection)
p3 = Point(3,1)
radius = 1
print( collection[1] ) # This works, BTW
p = collection[1]
print( p ) # These two work also!
for i in collection:
p = collection[i] # THIS FAILS
if distance(p3,p) < 2*radius:
print("Point "+collection[i]+" is too close to "+p3)
The file point.py contains:
import math
class Point:
'''Creates a point on a coordinate plane with values x and y.'''
COUNT = 0
def __init__(self, x, y):
'''Defines x and y variables'''
self.X = x
self.Y = y
def move(self, dx, dy):
'''Determines where x and y move'''
self.X = self.X + dx
self.Y = self.Y + dy
def __str__(self):
return "Point(%s,%s)"%(self.X, self.Y)
def __str__(self):
return "(%s,%s)"%(self.X,self.Y)
def testPoint(x=0,y=0):
'''Returns a point and distance'''
p1 = Point(3, 4)
print (p1)
p2 = Point(3,0)
print (p2)
return math.hypot(p1, p2)
def distance(self, other):
dx = self.X - other.X
dy = self.Y - other.Y
return math.sqrt(dx**2 + dy**2)
#p1 = Point(3,4)
#p2 = Point(3,0)
#print ("p1 = %s"%p1)
#print ("distance = %s"%(distance(p1, p2)))
Now, I have a couple of questions here to help me understand.
In the test case, why doesn't the print of the array use the str function to
print the Point out as '(x,y)'?
In ' if distance(p3,collection[i]) ', why isn't collection[i] recognized as a Point which the distance function is expecting?
In the 'p = collection[i]' statement, why does python complain that the list indices must be integers or slices, not Point?
It appears that the collection array is not recognized as an array of Point instances. I'm confused as in other OO languages like Objective-C or Java, these are simple things to do.
Take a look at this question. __repr__() is used when rendering things in lists.
(and 3.) I'm not sure if I follow your questions, but the problem you have in your code is that Python hands you the object itself, not the index. So:
for i in collection:
p = collection[i] # THIS FAILS
if distance(p3,p) < 2*radius:
print("Point "+collection[i]+" is too close to "+p3)
should be:
for p in collection:
if distance(p3,p) < 2*radius:
print(f"Point {p} is too close to {p3}")

TypeError: 'list' object is not callable , problem with passing generated array to second iteration

I am trying to run 500 iterations in optimization problem. I am doing some changes on pop array and than I am trying to pass it again to the next iteration, however run into error, tho the first iteration is working all fine, I get pop array and then pass it to created_moved_pop and create_star_pop and get some problems. Will be very thankful if someone could explain my why this happens
error trace
C:\Users\yuliy\PycharmProjects\method_deform_stars\venv\Scripts\python.exe C:/Users/yuliy/PycharmProjects/method_deform_stars/DS.py
[0.8575697060274371, 0.8802225709314421, 0.6098937002728221, 0.5482650148523068, 0.5395302259903021, 0.6330576538506912, 0.734280095260012, 0.6826885236666879, 0.5797401283594749, 0.8381278588403586, 0.4983449567579089, 0.37081148554598065, 0.19916270916904044, 0.7590390380364216, 0.8272752130297748, 0.8837021413140848, 0.9750382019031415, 0.5436068899712437, 0.6490739970397773, 0.3014768191053475]
Traceback (most recent call last):
File "C:/Users/yuliy/PycharmProjects/method_deform_stars/DS.py", line 70, in
star_pop = create_star_pop(pop)
[(0.11503376215798591, 6.794025806650792), (0.5133530350808552, 1.0230252795290697), (0.37081148554598065, 0.8887201815324006), (0.4201038734097051, 0.8215339609930865), (0.6098937002728221, 0.7952234761836543), (0.19916270916904044, 0.7689552603259296), (0.250319764137194, 0.7111682294644993), (0.3014768191053475, 0.7008819653567403), (0.6582300480283956, 0.6632231712798371), (0.6666685334677784, 0.658688271415733), (0.7646482839856097, 0.6322183223530311), (0.8120560994714594, 0.6155315414048562), (0.7590390380364216, 0.59962403681057), (0.8609150000772217, 0.569512653796447), (0.8083043720319294, 0.5354111445749077), (0.620024614496207, 0.4887918787850577), (0.5035114962372264, 0.4844464118877576), (0.8670977366853939, 0.48321853250106644), (0.5541193285153655, 0.4821747663938167), (0.8575697060274371, 0.47491541406252397)]
File "C:/Users/yuliy/PycharmProjects/method_deform_stars/DS.py", line 60, in create_star_pop
new_element = star_pop(population)
TypeError: 'list' object is not callable
[0.11503376215798591, 0.5133530350808552, 0.37081148554598065, 0.4201038734097051, 0.6098937002728221, 0.19916270916904044, 0.250319764137194, 0.3014768191053475, 0.6582300480283956, 0.6666685334677784, 0.7646482839856097, 0.8120560994714594, 0.7590390380364216, 0.8609150000772217, 0.8083043720319294, 0.620024614496207, 0.5035114962372264, 0.8670977366853939, 0.5541193285153655, 0.8575697060274371]
Process finished with exit code 1
import numpy as np
import math
import random
import operator
# Global variables
a = 0.1
b = 1
def function(x):
return (math.sin(40*math.pi*x)+math.pow(x-1, 4))/(2*x)
def initial_pop():
pop = np.random.uniform(a, b, 20)
pop = pop.tolist()
return pop
def moving_pop(population):
# e c
rand_item = population[random.randrange(len(population))]
# print(rand_item)
direction_arr = [-1, 1]
direction = direction_arr[random.randrange(len(direction_arr))]
# print(direction)
new_element = rand_item + direction * np.random.normal(0, 0.2)
if new_element > b:
extra = new_element - b
new_element = a + extra
if new_element < a:
extra = abs(new_element - a)
new_element = b - extra
# print(new_element)
return new_element
def create_moved_pop(population):
new_population = []
for x in range(0, 20):
new_element = moving_pop(population)
new_population.append(new_element)
# print(new_population)
return new_population
def star_pop(population):
random_item1 = population[random.randrange(len(population))]
random_item2 = population[random.randrange(len(population))]
while random_item2 == random_item1:
random_item2 = population[random.randrange(len(population))]
e_star = (random_item1 + random_item2)/2
return e_star
def create_star_pop(population):
star_population = []
for x in range(0, 20):
new_element = star_pop(population)
star_population.append(new_element)
# print(new_population)
return star_population
pop = initial_pop()
print(pop)
for i in range(0, 500):
moved_pop = create_moved_pop(pop)
star_pop = create_star_pop(pop)
pop_combined = sorted(sorted(pop) + sorted(moved_pop) +
sorted(star_pop))
y_array = []
for x in range(0, len(pop_combined)):
y_array.append(function(pop_combined[x]))
x_y_array = dict(zip(pop_combined, y_array))
sorted_x_y_array = sorted(x_y_array.items(), key=operator.itemgetter(1), reverse=True)
sorted_x_y_array = sorted_x_y_array[0:20]
print(sorted_x_y_array)
pop.clear()
for x in sorted_x_y_array:
pop.append(x[0])
print(pop)
you are re-defining star_pop as list
star_pop = create_star_pop(pop)
find the below fixed code
import numpy as np
import math
import random
import operator
# Global variables
a = 0.1
b = 1
def function(x):
return (math.sin(40*math.pi*x)+math.pow(x-1, 4))/(2*x)
def initial_pop():
pop = np.random.uniform(a, b, 20)
pop = pop.tolist()
return pop
def moving_pop(population):
# e c
rand_item = population[random.randrange(len(population))]
# print(rand_item)
direction_arr = [-1, 1]
direction = direction_arr[random.randrange(len(direction_arr))]
# print(direction)
new_element = rand_item + direction * np.random.normal(0, 0.2)
if new_element > b:
extra = new_element - b
new_element = a + extra
if new_element < a:
extra = abs(new_element - a)
new_element = b - extra
# print(new_element)
return new_element
def create_moved_pop(population):
new_population = []
for x in range(0, 20):
new_element = moving_pop(population)
new_population.append(new_element)
# print(new_population)
return new_population
def star_pop(population):
random_item1 = population[random.randrange(len(population))]
random_item2 = population[random.randrange(len(population))]
while random_item2 == random_item1:
random_item2 = population[random.randrange(len(population))]
e_star = (random_item1 + random_item2)/2
return e_star
def create_star_pop(population):
star_population = []
for x in range(0, 20):
new_element = star_pop(population)
star_population.append(new_element)
# print(new_population)
return star_population
pop = initial_pop()
print(pop)
for i in range(0, 500):
moved_pop = create_moved_pop(pop)
star_pop_ = create_star_pop(pop)
pop_combined = sorted(sorted(pop) + sorted(moved_pop) +
sorted(star_pop_))
y_array = []
for x in range(0, len(pop_combined)):
y_array.append(function(pop_combined[x]))
x_y_array = dict(zip(pop_combined, y_array))
sorted_x_y_array = sorted(x_y_array.items(), key=operator.itemgetter(1), reverse=True)
sorted_x_y_array = sorted_x_y_array[0:20]
print(sorted_x_y_array)
pop.clear()
for x in sorted_x_y_array:
pop.append(x[0])
print(pop)
You got a method called star_pop and an object called star_pop, in the 2nd iteration of the for loop you are trying
new_element = star_pop(population)
after doing
star_pop = create_star_pop(pop)
which returns a list
I think you mixed up your names. You can fix it by renaming either the function or the star_pop list.
Unrelated to that, you dont need to include the 0 in range(0, 500). Ranges always start at 0 by default.

Making a graph class iterate using a dictionary

I am trying to build a iterable graph class with python 2.7. I want to be able to iterate though a dictionary containing the vertexes.
Cutting and pasting from https://github.com/joeyajames has got me so far but now I am confused as to how to make this work so that
I can test vertices dict for the presence of an vertice and add if not present. This part is maybe unneeded.
"if (a not in gra ):" because the validation is done in the Graph class itself.
The expected output is a dictionary with the vertices as keys. Actualy im not even sure a list is not better object to use.
class Vertex(object):
def __init__(self, n):
self.name = n
self.neighbors = list()
self.discovery = 0
self.finish = 0
self.color = 'black'
def add_neighbor(self, v):
if v not in self.neighbors:
self.neighbors.append(v)
self.neighbors.sort()
class Graph(object):
def __init__(self,size):
self.vertices = {}
self.hops = 0
self.count = 0
self.limit = size
def __iter__(self):
return self
def next(self):
self.count += 1
if self.count > self.limit:
raise StopIteration
def add_vertex(self,vertex):
if isinstance(vertex, Vertex) and vertex.name not in self.vertices:
self.vertices[vertex.name] = vertex
return True
else:
return False
def add_edge(u,v):
if u in self.vertices and v in self.vertices:
for key, value in self.vertices.items():
if key == u:
value.add_neighbor(v)
if key == v:
value.add_neighbor(u)
return True
else:
return False
def _dfs(self, vertex):
global hops
vertex.color = 'red'
vertex.discovery = hops
hops += 1
for v in vertex.neighbors:
if self.vertices[v].color == 'black':
self._dfs(self.vertices[v])
vertex.color = 'blue'
vertex.finish = hops
time += 1
input = ((5,3),(4 ,2),(0,1),(2 3),(0 4))
N,l = input[0]
print "N is " + str(N)
print "l is " + str(l)
gra = Graph(N)
for i in xrange(1,l):
a,b = input[i]
# Store a and b as vertices in graph object
print "a is " + str(a) + " b is " + str(b)
if (a not in gra ):
print "adding a"
gra.add_vertex(Vertex(chr(a)))
if (b not in gra ):
print "adding b"
gra.add_vertex(Vertex(chr(b)))
You are trying to use not in, which tests for containment; implement the __contains__ hook to facilitate that:
def __contains__(self, vertex):
return vertex.name in self.vertices
I've assumed you wanted to test for vertices, so create one before testing for containment:
a = Vertex(chr(a))
if a not in gra:
print "adding a"
gra.add_vertex(a)
For iteration, I'd not make Graph itself the iterator; that limits you to iterating just once. Your next() method also lacks a return statement, so all you are doing is produce a sequence of None objects.
Make it an iterable instead, so return a new iterator object each time __iter__ is called. You can most simply achieve this by making __iter__ a generator:
def __iter__(self):
for vertex in self.vertices.itervalues():
yield vertex
Note the yield. I've assumed you wanted to iterate over the vertices.

'list' attribute has no attribute <function>

I am trying to create a class for Complex numbers that includes functions that operate on lists. I think my basic setup is okay because it works for functions that operate on single elements(like conjugate), but when I try to run functions like conjugateList, I get the error message "'list' object has no attribute 'conjugateList'. I am not sure how to address this problem. Thanks.
class Complex():
def __init__(self, real= 0.0, imaginary= 0.0):
self.real = real
self.imaginary = imaginary
def __str__(self):
if self.imaginary < 0:
printStr = str(self.real) + ' - ' + str(abs(self.imaginary))+ 'i'
else:
printStr = str(self.real) + ' + ' + str(self.imaginary)+ 'i'
return printStr
def conjugate(self):
result = Complex()
result.real = self.real
result.imaginary = (self.imaginary * (-1))
return result
def conjugateList(lstC):
newLst = []
for elem in lstC:
elem = elem.conjugate()
newLst += elem
return newLst
Because the conjugateList method isn't on your list, it's on the Complex object.
Note that this conjugateList method should actually be a staticmethod or — better yet — a function.
You would do:
class Complex():
# The rest of your stuff
#staticmethod
def conjugateList(lstC):
newLst = []
for elem in lstC:
elem = elem.conjugate()
newLst += elem
return newLst
And then,
l1 = [Complex(1,1), Complex(1,2)]
l2 = Complex.conjugateList(l1)
Short of learning purposes for class design, for production you might want to use numpy:
>>> import numpy as np
>>> comps = np.array([complex(1, 1), complex(1, 2)])
>>> comps.dtype
dtype('complex128')
>>> comps.conjugate()
array([ 1.-1.j, 1.-2.j])

list with infinite elments

I need to operate on two separate infinite list of numbers, but could not find a way to generate, store and operate on it in python.
Can any one please suggest me a way to handle infinite Arithmetic Progession or any series and how to operate on them considering the fact the minimal use of memory and time.
Thanks every one for their suggestions in advance.
You are looking for a python generator instead:
def infinitenumbers():
count = 0
while True:
yield count
count += 1
The itertools package comes with a pre-built count generator.
>>> import itertools
>>> c = itertools.count()
>>> next(c)
0
>>> next(c)
1
>>> for i in itertools.islice(c, 5):
... print i
...
2
3
4
5
6
This is where the iterator comes in. You can't have an infinite list of numbers, but you can have an infinite iterator.
import itertools
arithmetic_progression = itertools.count(start,step) #from the python docs
The docs for Python2 can be found here
I have another python3 solution (read SICP chapter 3.5)
class Stream:
def __init__(self, head, tail):
self.head = head
self.tail = tail
self.memory = None
self.isDone = False
def car(self):
return self.head
def cdr(self):
if self.isDone:
return self.memory
self.memory = self.tail()
self.isDone = True
return self.memory
def __getitem__(self, pullFrom):
if pullFrom < 1 or self.memory == []:
return []
return [self.car()] + self.cdr()[pullFrom - 1]
def __repr__(self):
return "[" + repr(self.car()) + " x " + repr(self.tail) + "]"
def map(self, func):
if self.memory == []:
return []
return Stream(func(self.car()), lambda: Stream.map(self.cdr(), func))
def from_list(lst):
if lst == []:
return []
return Stream(lst[0], lambda:
Stream.from_list(lst[1:]))
def filter(self, pred):
if self.memory == []:
return []
elif pred(self.car()):
return Stream(self.car(), lambda: Stream.filter(self.cdr(), pred))
else:
return self.cdr().filter(pred)
def sieve(self):
return Stream(self.car(), lambda: self.cdr().filter(lambda n: n % self.car() > 0).sieve())
def foreach(self, action, pull = None):
if pull is None:
action(self.car())
self.cdr().foreach(action, pull)
elif pull <= 0:
return
else:
action(self.car())
self.cdr().foreach(action, pull-1)and run:
a = Stream(0, lambda: a.map((lambda x: x + 1)))
print(a[10])
which returns:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] .
But streams are lazily evaluated, so:
>>> a = Stream(0, lambda: a.map((lambda x: x + 1)))
>>> print(a)
prints:
[0 x [...]]
To create an object that acts like a "mutable" infinite list, you can overload the __getitem__ and __setitem__ methods in a class:
class infinite_list():
def __init__(self, func):
self.func = func
self.assigned_items = {}
def __getitem__(self, key):
if key in self.assigned_items:
return self.assigned_items[key]
else:
return self.func(key)
def __setitem__(self, key , value):
self.assigned_items[key] = value
Then, you can initialize the "infinite list" with a lambda expression and modify an item in the list:
infinite_thing = infinite_list(lambda a: a*2)
print(infinite_thing[1]) #prints "2"
infinite_thing[1] = infinite_thing[2]
print(infinite_thing[1]) #prints "4"
Similarly, it is possible to create an "infinite dictionary" that provides a default value for each missing key.
Perhaps the natural way to generate an infinite series is using a generator:
def arith(a, d):
while True:
yield a
a += d
This can be used like so:
print list(itertools.islice(arith(10, 2), 100))
My solution is:
from hofs import *
def cons_stream(head,tail):
return [head,tail,False,False]
def stream_cdr(strm):
if strm[2]:
return strm[3]
strm[3] = strm[1]()
strm[2] = True
return strm[3]
def show_stream(stream, num = 10):
if empty(stream):
return []
if num == 0:
return []
return adjoin(stream[0], show_stream(stream_cdr(stream), num - 1))
def add_streams(a , b):
if empty(a):
return b
if empty(b):
return a
return cons_stream(a[0] + b[0] , lambda : add_streams( stream_cdr(a), stream_cdr(b)))
def stream_filter( pred , stream ):
if empty(stream):
return []
if pred(stream[0]):
return cons_stream(stream[0], lambda : stream_filter(pred, stream_cdr(stream)))
else:
return stream_filter( pred , stream_cdr( stream ))
def sieve(stream):
return cons_stream(stream[0] , lambda : sieve(stream_filter(lambda x : x % stream[0] > 0 , stream_cdr(stream))))
ones = cons_stream(1, lambda : ones)
integers = cons_stream(1, lambda : add_streams(ones, integers))
primes = sieve(stream_cdr(integers))
print(show_stream(primes))
Copy the Python code above.
When I tried it, i got [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] which is 10 of an infinite list of primes.
You need hofs.py to be
def empty(data):
return data == []
def adjoin(value,data):
result = [value]
result.extend(data)
return result
def map(func, data):
if empty(data):
return []
else:
return adjoin(func(data[0]), map(func, data[1:]))
def keep(pred, data):
if empty(data):
return []
elif pred(data[0]):
return adjoin( data[0] , keep(pred, data[1:]))
else:
return keep(pred, data[1:])
I assume you want a list of infinite numbers within a range. I have a similar problem, and here is my solution:
c = 0
step = 0.0001 # the difference between the numbers
limit = 100 # The upper limit
myInfList = []
while c <= limit:
myInfList.append(c)
c = c + step
print(myInfList)

Categories