I am trying to use extend to save data calculated from loop iterations. However, I get the error 'numpy.int64' object is not iterable
x_hat1= commpy.channels.bsc(x[1],0.2)
Distance = []
for i in range(1, 6):
Distance.extend(hamming_distance(x_hat1,x[i]))
So, I tried adding the loop inside the extend itself as follows
Distance.extend(value for i in range(1, 6), hamming_distance(x_hat1,x[i]))
But I get the error Generator expression must be parenthesized if not sole argument. I checked the parenthesis a couple of times and they are correct. So, I don't know what is wrong.
Briefly, I want to find the hamming distances between one vector and several ones, and save it in the list "Distance" to use it later on.
Thanks
Your problem is extend expects a list as an argument. If you want to use a normal for loop, either make a single element list:
x_hat1= commpy.channels.bsc(x[1],0.2)
Distance = []
for i in range(1, 6):
Distance.extend([hamming_distance(x_hat1,x[i])])
or use append instead of extend: Distance.append(hamming_distance(x_hat1,x[i])).
If you want to use an implicit for loop, as in your second case, you simply need to restructure your statement.
The reference to i should come before the implicit loop:
Distance.extend(hamming_distance(x_hat1,x[i]) for i in range(1, 6))
Any of these options will work, it's up to you which you would prefer. (Personally the implicit loop is my favorite. It's a one-liner, not to mention much more pythonic than the straight for loop.)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
More info on list.extend vs. the list.append functions in python (as that was your main confusion):
Append:
Appends a single object to the end of a list
Examples:
>>myList = [1,2,3]
>>myList.append(4)
>>myList
[1,2,3,4]
BUT should not be used to add a whole list of elements
>>myList = [1,2,3]
>>myList.append([4,5,6])
>>myList
[1,2,3,[4,5,6]]
More info/examples:
http://www.tutorialspoint.com/python/list_append.htm
Extend:
Extends a list by using list.append on each element of the passed list
Examples:
>>myList = [1,2,3]
>>myList.extend(4)
>>myList
[1,2,3,4,5,6]
BUT throws an error if used on a single element
>>myList = [1,2,3]
>>myList.extend(4)
Type Error: 'int' object is not iterable
To extend a single element requires you to make a 1-item list: myList.extend([4])
More info/examples:
http://www.tutorialspoint.com/python/list_extend.htm
More on the differences:
append vs. extend
Related
class test(object):
def __init__(self, name):
self.name = ''
testList = [(test("empty") for i in range(3)) for j in range(2)]
for m in range(3):
for n in range(2):
testList[m][n].name = "changed"
I'm trying to check and change items of a 2-dimensional list which contains objects only. I built 2d list first and tried to affect the items in it with double for-loop but it returns TypeError.
Traceback (most recent call last):
File "test.py", line 12, in <module>
testList[m][n].name = "changed"
TypeError: 'generator' object is not subscriptable
I really couldn't understand what's going on here as it seems quite simple and viable. The script could not run with testList[0][0].name = "changed" (instead of testList[m][n]) so I suspect that the loop is not allowed to run like this. But why?
When you type (foo for i in bar) you get a generator, when you type [foo for i in bar] you get a list. The difference between these two is that the generator create elements (generate) as it is traversed, while a list hold all items on memory. This is why (i for i in range(10))[2] is not possible, while [i for i in range(10)][2] is.
You should use generators when the whole set of items are too big to keep in memory or simply when you don't need them all in memory at same time. They are good for traversing files while keeping constant memory usage for example.
Now if you want to subscript something, like foo[some_index] then foo need to be subscriptable and generators aren't because doing so would throw away the whole point of generator existence. While someone may arg that (i for i in range(10))[2] is okay, expanding some generators may end up in infinite loop, for example:
from itertools import count
even = (i for i in count() if i % 2 == 0)
This is perfect valid code. The count() returns an infinite generator. If we can argue that even[1] would be 2 what would be even[-1]? There is no last even number. So the computation would take forever.
Anyway. Generators are common in python and sooner or later you'll need to convert then to a list or a tuple, you can do this by passing they to the list or tuple constructor list(range(10)) or tuple(range(10)).
Now I think that we have enough background to answer your question. You are doing this testList = [(test("empty") for i in range(3)) for j in range(2)] which gives us a list of generators. So testList[m][n] reduces to something like (test("empty") for i in range(3))[n] which is where things blow up.
If you just replace parenthesis by brackets you solve your problem, so testList = [[test("empty") for i in range(3)] for j in range(2)].
You didn't create a list of lists, you created a list of generator objects. Those generator objects are lying dormant, they are not active until code iterates over them. Even then, you don't have a sequence, which is what is required to use indexing. To be able to assign to indexes you need a mutable sequence.
If you want to make each nested index mutable, you have to generate lists, not generators. Replace the (...) parentheses with [...] square brackets to create a list comprehension instead:
testList = [[test("empty") for i in range(3)] for j in range(2)]
List comprehensions are executed immediately, there and then, producing a list object. Lists are mutable sequences.
I have a function (in the example: some_function()) that returns a set. I got a data structure of some elements (in the example arr) and need to map the elements to the function and I want to get back a set of all elements. Not a set of sets but a set of all the elements that are in the sets. I know that some_function() only returns one dimensional sets.
I tried to use map but didn't quite get it to work, I got it to work with list comprehensions but I don't really like my solution.
Is it possible to not create a list and then unpack it?
Or can I somehow convert what I get from my map approach without much work?
Example:
arr = [1, 2, 3]
# I want something like this
set.union(some_function(1), some_function(2), some_function(3))
# where some_function returns a set
# this is my current solution
set.union(*[some_function(el) for el in arr]))
# approach with map, but I couldn't convert it back to a set
map(some_function, arr)
You can use a generator expression instead of a list comprehension so that you don't have to create a temporary list first:
set.union(*(some_function(el) for el in arr)))
or, using map:
set.union(*map(some_function, arr))
I think your current solution is fine. If you want to avoid creating a list, you may try:
set.union(*(some_function(el) for el in arr)))
In Python, sometimes you just have to not be fancy.
result = set()
for el in arr:
result.update(some_function(el))
This approach doesn’t create a list of the return values and so doesn’t hold onto sets longer than necessary. You can wrap it in a function for cleanliness.
I am trying to append objects to the end of a list repeatedly, like so:
list1 = []
n = 3
for i in range(0, n):
list1 = list1.append([i])
But I get an error like: AttributeError: 'NoneType' object has no attribute 'append'. Is this because list1 starts off as an empty list? How do I fix this error?
This question is specifically about how to fix the problem and append to the list correctly. In the original code, the reported error occurs when using a loop because .append returns None the first time. For why None is returned (the underlying design decision), see Why do these list operations return None, rather than the resulting list?.
If you have an IndexError from trying to assign to an index just past the end of a list - that doesn't work; you need the .append method instead. For more information, see Why does this iterative list-growing code give IndexError: list assignment index out of range? How can I repeatedly add elements to a list?.
If you want to append the same value multiple times, see Python: Append item to list N times.
append actually changes the list. Also, it takes an item, not a list. Hence, all you need is
for i in range(n):
list1.append(i)
(By the way, note that you can use range(n), in this case.)
I assume your actual use is more complicated, but you may be able to use a list comprehension, which is more pythonic for this:
list1 = [i for i in range(n)]
Or, in this case, in Python 2.x range(n) in fact creates the list that you want already, although in Python 3.x, you need list(range(n)).
You don't need the assignment operator. append returns None.
append returns None, so at the second iteration you are calling method append of NoneType. Just remove the assignment:
for i in range(0, n):
list1.append([i])
Mikola has the right answer but a little more explanation. It will run the first time, but because append returns None, after the first iteration of the for loop, your assignment will cause list1 to equal None and therefore the error is thrown on the second iteration.
I personally prefer the + operator than append:
for i in range(0, n):
list1 += [[i]]
But this is creating a new list every time, so might not be the best if performance is critical.
Note that you also can use insert in order to put number into the required position within list:
initList = [1,2,3,4,5]
initList.insert(2, 10) # insert(pos, val) => initList = [1,2,10,3,4,5]
And also note that in python you can always get a list length using method len()
Like Mikola said, append() returns a void, so every iteration you're setting list1 to a nonetype because append is returning a nonetype. On the next iteration, list1 is null so you're trying to call the append method of a null. Nulls don't have methods, hence your error.
use my_list.append(...)
and do not use and other list to append as list are mutable.
I am trying to append objects to the end of a list repeatedly, like so:
list1 = []
n = 3
for i in range(0, n):
list1 = list1.append([i])
But I get an error like: AttributeError: 'NoneType' object has no attribute 'append'. Is this because list1 starts off as an empty list? How do I fix this error?
This question is specifically about how to fix the problem and append to the list correctly. In the original code, the reported error occurs when using a loop because .append returns None the first time. For why None is returned (the underlying design decision), see Why do these list operations return None, rather than the resulting list?.
If you have an IndexError from trying to assign to an index just past the end of a list - that doesn't work; you need the .append method instead. For more information, see Why does this iterative list-growing code give IndexError: list assignment index out of range? How can I repeatedly add elements to a list?.
If you want to append the same value multiple times, see Python: Append item to list N times.
append actually changes the list. Also, it takes an item, not a list. Hence, all you need is
for i in range(n):
list1.append(i)
(By the way, note that you can use range(n), in this case.)
I assume your actual use is more complicated, but you may be able to use a list comprehension, which is more pythonic for this:
list1 = [i for i in range(n)]
Or, in this case, in Python 2.x range(n) in fact creates the list that you want already, although in Python 3.x, you need list(range(n)).
You don't need the assignment operator. append returns None.
append returns None, so at the second iteration you are calling method append of NoneType. Just remove the assignment:
for i in range(0, n):
list1.append([i])
Mikola has the right answer but a little more explanation. It will run the first time, but because append returns None, after the first iteration of the for loop, your assignment will cause list1 to equal None and therefore the error is thrown on the second iteration.
I personally prefer the + operator than append:
for i in range(0, n):
list1 += [[i]]
But this is creating a new list every time, so might not be the best if performance is critical.
Note that you also can use insert in order to put number into the required position within list:
initList = [1,2,3,4,5]
initList.insert(2, 10) # insert(pos, val) => initList = [1,2,10,3,4,5]
And also note that in python you can always get a list length using method len()
Like Mikola said, append() returns a void, so every iteration you're setting list1 to a nonetype because append is returning a nonetype. On the next iteration, list1 is null so you're trying to call the append method of a null. Nulls don't have methods, hence your error.
use my_list.append(...)
and do not use and other list to append as list are mutable.
I'm working through a tutorial which includes this code:
for position, target in population_gen(population):
pos = float(position)
all_inputs.append([random.random(), pos * factor])
all_targets.append([target])
I don't fully understand how the for loop works. In particular: what is the loop iterating through exactly? I'm only familiar with simple examples like for i in mylist:. How can there be a function call on the right-hand side of in, and two things separated by a comma on the left-hand side?
The function population_gen is returning a list of tuples, which are unpacked automatically into variable names using this syntax.
So basically, you're getting something like the following as return value from the function:
[("pos1", "target1"), ("pos2", "target2"), ]
Given this example, in the the for loop's first iteration, the variables "position" and "target" will have the values:
position = "pos1"
target = "target1"
In second iteration:
position = "pos2"
target = "target2"
Tuple unpacking.
for a, b in [(1, 2), (3, 4)]:
print a
print b
print 'next!'
And the function is just a function.
The function either returns a sequence or serves as something called a "generator:" it spits out successive elements in a sequence for the caller to iterate through. This question concerning the yield keyword has some thorough discussion of how these work.
As for the comma, since the function (apparently) returns a two-tuple, the comma-separated list of names is a convenient way to name individual elements of the tuple without having to unpack them yourself.
It's called tuple unpacking. The population_gen (generator) function yields tuples containing exactly two elements. In python, you can assign several variables to tuples like this
a, b = (1, 2)
So in this for loop, you directly put the two tuple values from the current iteration item into your two variables position and target.