Why do i get <map object at 0x0389DCD0> when using map - python

What i have understood so far from the map function is that it applies a given function to each item in an iterable and returns the list of the result.
def square(num):
return num**2
list_num = [1,2,3,4]
considering the above function and the list of numbers as an example.
if we: list(map(square,list_num)) we will get as an output [1,4,9,16].
now comes the part that i am not able to find a sensible explenation of, if i
print(map(square,list_num)) i will get as an output <map object at 0x038B0290>.
My question is, Why am i getting the memory location and not a list when i use the print() function or when use map(square,list_num).

map doesn't return a list. It returns a map object that lazily produces results as needed:
print(type(map(int, [1])))
<class 'map'>
It also doesn't override the stringify method which would produce pretty-printed results. That may be because that would require forcing the entire list to be evaluated, and if that's acceptable in your program, you probably shouldn't be using map in the first place; unless you're debugging, in which case use of list is probably fine unless you're dealing with an infinite list.
If you want a full-element print out, explicitly force it by placing it in a list before printing as you saw, or use a strict list production method like a list comprehension.

Related

Understanding Python Maps()

So I am trying to figure out how Python's map() function works as a way to speed up my program a little bit. From my basic understanding it looks like you can use map() to replace certain instances where you'd use a for loop. What I'm curious about is can you change something like:
loopNum = 25
for i in range (loopNum):
self.doSomething()
To:
loopNum = 25
map(self.doSomething(), range(loopNum))
Additionally, in the above example, would I be able to forego that loopNum variable, and in the map just have map(something, 25)?
No, you can't as map(function, iterable) applies function to each element of the iterable. If you simply want to execute some functionn times, just use a loop.
Note that iterable must be (surprise!) an iterable, not a number.
map is roughly the equivalent of this for loop:
# my_map(func, iter1, iterN...)
def my_map(func, *iteables)
for x, y,... in zip(iter1, iter2,iterN...):
yield func(x,y,...)
What you're doing in your code is just like this:
my_map(self.doSomething(), range(loopNum))
self.dSomething() must return a function or a callable object or this obviously doesn't work. This is because, whatever object you pass into the func argument of my_map function will be called then in addition to passing the right number of arguments to func, func must be a callable object as well :-)
*You must iterate over the iterable returned by map to obtain the results, otherwise, you would just get an iterable object without tangible work.
I want to add to this question that map() is virtually never the right tool in Python. Our BDFL himself, wanted to remove it from Python 3, together with lambdas and, most forcefully reduce.
In almost all cases where you feel tempted to use map() take a step back and try to rewrite your code using list comprehension instead. For your current example, that would be:
my_list = [self.doSomething() for i in range(loopNum)]
or
my_generator = (self.doSomething() for i in range(loopNum))
to make it a generator instead.
But for this to make any sense at all, self.doSomething() should probably take the variable i as an input. After all you are trying to map the values in your range to something else.

Set changed size during iteration

I'm new to python coming from a c++ background. I was just playing around with sets trying to calculate prime numbers and got a "Set changed size during iteration" error.
How internally does python know the set changed size during iteration?
Is it possible to do something similar in user defined objects?
The pythonic way to filter sets, lists or dicts is with list [or dict] expressions
your_filtered_set = set([elem for elem in original_set if condition(elem)])
It's trivial to do so with a user-defined object: just set a flag each time you modify the object, and have the iterator check that flag each time it tries to retrieve an item.
Generally, you should not modify a set while iterating over it, as you risk missing an item or getting the same item twice.

Sorting a list of lists with itertools imap in Python

I'm wondering what's happening when I execute this code and also if there is a better way to accomplish the same task. Is a list of lists being made in memory to preform the sort, and then bar is assigned to be an iterator of foo.values()? Or possibly foo.values() is sorted in the allotted dictionary memory space (seems unlikely)?
Imagine the first value in the list, the integer, refers to a line number in a file. I want to open the file and update only the lines referenced in the foo.values() lists with the rest of the data in the list (EG update line 1 with strings '123' and '097').
from itertools import imap
>>> foo = {'2134':[1, '123', '097'], '6543543':[3, '1'], '12315':[2, '454']}
>>> bar = imap([].sort(), foo.values())
Thanks~
First, you're passing [].sort(), which is just None, as the first argument to imap, meaning it's doing nothing at all. As the docs explain: "If function is set to None, then imap() returns the arguments as a tuple."
To pass a callable to a higher-order function like imap, you have to pass the callable itself, not call it and pass the result.
Plus, you don't want [].sort here; that's a callable with no arguments that just sorts an empty list, which is useless.
You probably wanted list.sort, the unbound method, which is a callable with one argument that will sort whatever list it's given.
So, if you did that, what would happen is that you'd creating an iterator that, if you iterated it, would generate a bunch of None values and, as a side effect, sort each list in foo.values(). No new lists would be created anywhere, because list.sort mutates the list in-place and returns None.
But since you don't ever iterate it anyway, it hardly matters what you put into imap; what it actually does is effectively nothing.
Generally, abusing map/imap/comprehensions/etc. for side-effects of the expressions is a bad idea. An iterator that generates useless values, but that you have to iterate anyway, is a recipe for confusion at best.
The simple thing to do here is to just use a loop:
for value in foo.values():
value.sort()
Or, instead of sorting in-place, generate new sorted values:
bar = imap(sorted, foo.values())
Now, as you iterate bar, each list will be sorted and given to you, so you can use it. If you iterate this, it will generate a sorted list in memory for each list… but only one will ever be alive at a time (unless you explicitly stash them somewhere).

Correct way to iterate twice over a list?

What is the correct way to perform multiple iteration over a container? From python documentation:
Iterator - A container object (such as a list) produces a fresh new
iterator each time you pass it to the iter() function or use it in a
for loop. Attempting this with an iterator will just return the same
exhausted iterator object used in the previous iteration pass, making
it appear like an empty container.
The intention of the protocol is that once an iterator’s next() method
raises StopIteration, it will continue to do so on subsequent calls.
Implementations that do not obey this property are deemed broken.
(This constraint was added in Python 2.3; in Python 2.2, various
iterators are broken according to this rule.)
If I have this code:
slist = [1,2,3,4]
rlist = reversed(slist)
list(rlist)
#[4,3,2,1]
tuple(rlist)
#()
What would be the easiest and most correct way to iterate over 'rlist' twice?
rlist = list(reversed(slist))
Then iterate as often as you want. This trick applies more generally; whenever you need to iterate over an iterator multiple times, turn it into a list. Here's a code snippet that I keep copy-pasting into different projects for exactly this purpose:
def tosequence(it):
"""Turn iterable into a sequence, avoiding a copy if possible."""
if not isinstance(it, collections.Sequence):
it = list(it)
return it
(Sequence is the abstract type of lists, tuples and many custom list-like objects.)
I wouldn't stored the list twice, if you can not combine it to iterate once, then I would
slist = [1,2,3,4]
for element in reversed(slist):
print element # do first iteration stuff
for element in reversed(slist):
print element # do second iteration stuff
Just think of the reversed() as setting up a reverse iterator on slist. The reversed is cheap. That being said, if you only ever need it reversed, I would reverse it and just have it stored like that.
What is the correct way to perform multiple iteration over a container?
Just do it twice in a row. No problem.
What would be the easiest and most correct way to iterate over 'rlist' twice?
See, the reason that isn't working for you is that rlist isn't "a container".
Notice how
list(slist) # another copy of the list
tuple(slist) # still works!
So, the simple solution is to just ensure you have an actual container of items if you need to iterate multiple times:
rlist = list(reversed(slist)) # we store the result of the first iteration
# and then that result can be iterated over multiple times.
If you really must not store the items, try itertools.tee. But note that you won't really avoid storing the items if you need to complete one full iteration before starting the next. In the general case, storage is really unavoidable under those restrictions.
Why don't you simply reverse the original list in-place (slist.reverse()), then iterate over it as many times as you wish, and finally reverse it again to obtain the original list once again?
If this doesn't work for you, the best solution for iterating over the list in reversed order is to create a new reverse iterator every time you need to iterate
for _ in xrange(as_many_times_as_i_wish_to_iterate_this_list_in_reverse_order):
for x in reversed(slist):
do_stuff(x)

Python: Return tuple or list?

I have a method that returns either a list or a tuple. What is the most pythonic way of denoting the return type in the argument?
def names(self, section, as_type=()):
return type(as_type)(([m[0] for m in self.items(section)]))
The pythonic way would be not to care about the type at all. Return a tuple, and if the calling function needs a list, then let it call list() on the result. Or vice versa, whichever makes more sense as a default type.
Even better, have it return a generator expression:
def names(self, section):
return (m[0] for m in self.items(section))
Now the caller gets an iterable that is evaluated lazily. He then can decide to iterate over it:
for name in obj.names(section):
...
or create a list or tuple from it from scratch - he never has to change an existing list into a tuple or vice versa, so this is efficient in all cases:
mylist = list(obj.names(section))
mytuple = tuple(obj.names(section))
Return whatever the caller will want most of the time. If they will want to be able to sort, remove or delete items, etc. then use a list. If they will want to use it as a dictionary key, use a tuple. If the primary use will be iteration, return an iterator. If it doesn't matter to the caller, which it won't more often than you might think, then return whatever makes the code the most straightforward. Usually this will be a list or an iterator.
Don't provide your own way to convert the output to a given type. Python has a perfectly simple way to do this already and any programmer using your function will be familiar with it. Look at the standard Python library. Do any of those routines do this? No, because there's no reason to.
Exception: sometimes there's a way to get an iterator or a list, even though it is easy to convert an iterator to a list. Usually this capability is provided as two separate functions or methods. Maybe you might want to follow suit sometimes, especially if you could implement the two alternatives using different algorithms that provide some clear benefit to callers who want one or another.
Keep it simple:
def names(self, section):
"""Returns a list of names."""
return [m[0] for m in self.items(section)]
If the caller wants a tuple instead of a list, he does this:
names = tuple(obj.names(section))

Categories