Don't understand this python For loop - python

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.

Related

How to access a tuple inside a tuple with a range in python?

I am working on a Playfair cipher project in python and I need to access a tuple which is inside a tuple it is a table in my programs context and I need to add letters in it but am confused on how I would navigate through it. When I mean navigate I mean, how to read the tuple inside the tuple to see how many letters are in each tuple, how to add a letters in each of the tuples and how to move on to the next tuple.
Here is the tuple inside a tuple that I am talking about:
self.__table = (tuple(table[0:5]), tuple(table[5:10]),
tuple(table[10:15]), tuple(table[15:20]),
tuple(table[20:25]))
Here is the link to the entire code if that helps (the one my professor gave me): https://gist.github.com/roshanlam/3d1d495c42a92ca96a961655b9276651
Suppose a sample tuple of tuples is x as given below, then you can access individual elements like this:
x = ((1,6,0),(2,3),(4,9,6,5,10))
for item in x:
print(len(item)) #length of item tuple
for i in item:
print(i) #prints individual elements of tuple

What exactly is going on here? (Python 3.7.6)

I'm studying someone else's solution on Codewars and am a little puzzled about something. Here is a link to the original question: Reverse or Rotate?. Credit goes to the original author, falsetru.
Here's the solution:
def revrot(strng, sz):
return ''.join(
chunk[1:] + chunk[:1] if sum(int(d)**3 for d in chunk) % 2 else chunk[::-1]
for chunk in map(''.join, zip(*[iter(strng)]*sz))
)
I think I understand most of it. Except for this part:
zip(*[iter(strng)]*sz)
I think that the * used in this way signifies a non-keyworded variable-length argument list - meaning that there could be any number of pieces of the original string (strng), which are of length sz, for example, 6. The zip() function is receiving some variable number of iterables, which is what it requires, per the documentation. (Right?)
So then, map(''.join, zip(*[iter(strng)]*sz) first returns an iterator for the string strng. It returns this inside of a list. It seems like that list is then multiplied by sz (why?). It returns a variable number of results to zip (thus the *). zip() returns a tuple (I guess?), which is then passed through the join function via map.
Questions:
Is that even close to being right?
Why must iter(strng) be placed inside a list []?
Why can you join the result of zip? I tried joining ('m',) as a test and got 'm'. Confused as to why that works as well.
Can someone explain more about the *? I'm confused as to when I should use it...
Thanks. I'm still a late beginner in Python so I appreciate the help! (Even for just a piece of my question!)
To understand what is happening, we want to analyze the statement
for chunk in map(''.join, zip(*[iter(strng)]*sz))
Inside out:
iter(strng) returns an iterator that each time is accessed using next or in an loop consumes an element (a character) of strng and returns said element.
[iter(strng)] is a list, its unique element is the iterator
[iter(strng)]*sz is the concatenation of sz copies of the list, [iter(strng), ..., iter(strng)] containing sz times the same iterator object, I mean literally the same iterator object.
*[iter(strng)]*sz is equivalent to *[iter(strng), ..., iter(strng)] and, when used in a function argument list, unpacks its contents: the function sees its list of arguments as (iter(strng), ..., iter(strng)).
zip(*[iter(strng)]*sz) is hence equivalent to zip(iter(strng), ..., iter(strng)).
At each iteration zip takes the first element of each of its arguments and place them in a tuple, but because the various references to iter all refer to the same, original instance of iter(strng) the first tuple returned by zip contains the first sz characters of strng, the second contains the sz+1 to 2*sz characters etc etc.
Finally, each of this tuples is the argument of ''.join(), so we have a series of strings each long sz characters, spanning the original strng.
That's it.

How to print a list of function values from a generating function in python?

I'm new to python and just starting to learn the basics.
I have defined a function recursively and I want to print a list of function outputs.
This is the code:
def x(n):
assert n>=0, "Only non-negative integers n are allowed"
if n == 0:
return 5
else:
return (x(n-1)+5)/x(n-1)
print([x(0),x(1),x(2)])
for k in range(0,9,1):
print(x(k))
So my question is: say I want to print a list of the first 10 outputs of the sequence/function, i.e. x(0),...,x(9), how do I do this without actually listing each output manually? I want them to be in the form "[x(0),...,x(9)]", just like I did for the first 3 values. My attempt is in the last command of the program, where k moves from 0 to 9. The last command clearly prints the first 10 outputs, but not as a list, i.e. in [] brackets.
Any input is greatly appreciated.
One Solution:
I replaced the code
for k in range(0,9,1):
print(x(k))
with
print([x(k) for k in range(9)])
This puts the outputs in a list, i.e. in the [ ] brackets. Worked wonderfully!
You can use list comprehension.
print([x(n) for n in range(9)])
# outputs: [5, 2.0, 3.5, 2.4285714285714284, 3.058823529411765, 2.634615384615384, 2.8978102189781025, 2.72544080604534, 2.83456561922366]
Explanation:
We're making a list out by calling the function x() for each of the numbers (n) that are in the range from 0 to 9 (not included).
Please note that it is implicit that the starting point of the range() function is 0, that the step is 1, and the endpoint (9) is not included.
Here's a solution for a beginner (not an one-liner, should be easier to understand):
myarray = []
for i in range(9):
myarray.append(x(i))
Just to show the alternative to a list comprehension using map, since this is practically the scenario that map was made for:
xs = map(x, range(9))
map takes a function, and applies it to each member of the supplied iterable.
The main difference between this and using a comprehension is this returns a lazy iterable (a map object), not a list. x will not be applied to an element until you request the element.
Use of a list comprehension/generator expression is preferable in the majority of scenarios, but map is nice if you need/can tolerate a lazy result, and you already have a predefined function.

Adding value to a list in a tuple [duplicate]

This question already has answers here:
Why can tuples contain mutable items?
(8 answers)
Closed 6 years ago.
Here's 2 pieces of Python code:
t = (1, [2])
t[1] += [3]
and
t = (1, [2])
t[1].append(3)
The first piece firstly modifies the inner list t[1], and than throws an exception while trying to reassign value in the tuple. Though value of t has actually changed, this behaviour is more or less understandable. But the second piece of code changes the tuple without any error/exception/whatever (as I understand, because it changes list t[1] without reassignment).
The question is, doesn't this stuff contradict the immutability of tuples?
Tuples are immutable which means you cannot update or change the
values of tuple elements. You are able to take portions of existing
tuples to create new tuples as the following example demonstrates −
#!/usr/bin/python
tup1 = (12, 34.56);
tup2 = ('abc', 'xyz');
# Following action is not valid for tuples
# tup1[0] = 100;
# So let's create a new tuple as follows
tup3 = tup1 + tup2;
print tup3
When the above code is executed, it produces the following result −
(12, 34.56, 'abc', 'xyz')
But when you access the list in the tuple like t[1], you access the object reference which allows you use class functions. The immutable one is tuple, not the contained object.
I think the only thing you are missing is that "tuple is immutable" only means you can't change the references for the elements of the tuple. If an element is mutable, you can still mutate it.
The main rule here is: "A tuple itself is immutable. Its content, not."
When you are calling the append method, you're modifying an element of the tuple, not the tuple itself. So, the call is valid. You can see it in that sample:
tab = (new Object(), new Object(), new Object())
tab[1].changeContent();
Now, just replace the changeContent with the append method and you will see why it's valid. The value tab[1] still references the same object. But the object itself have changed.
But, when you are using the "plus" operator, it's not the same case.
When you call
tab[0] += [1]
It's rewritten as something like (if you suppose that "addWith" is the function that returns the result of the addition):
tab[0] = tab[0].addWith([1])
As you can see that it's modifying the tuple itself (it links the first cell to another object), it's why the call is invalid.

Understanding the python code snippet

Please help me understand the following code snippet :-
def any(l):
"whether any number is known from list l"
s = set(list(l)[0])
for x in l:
s.intersection_update(set(x))
return len(s) > 0
Here l is a list containing the list of 3-tuples e.g [(17,14,13),(19,17,2),(22,11,7),(22,13,1),(23,10,5),(23,11,2),(25,5,2)] etc.
In particular I am facing difficulty understanding the line 3
s=set(list(l)[0])
set(list(l)[0])
list(l) creates a new list from land then [0] is to fetch its first item, which is (17,14,13).
and then set((17,14,13)) returns a set of this tuple.
set is a data structure which contains only unique hash-able elements.
i.e set((10,12,10)) equals {10,12}
>>> l=[(17,14,13),(19,17,2),(22,11,7),(22,13,1),(23,10,5),(23,11,2),(25,5,2)]
>>> list(l)[0]
(17, 14, 13)
>>> set(list(l)[0])
{17, 13, 14}
In s=set(list(l)[0]), you're creating a set from the first element of the list. In your case, you could have used set(l[0]) and it would do the same thing. Essentially, you're creating a set based on the first tuple of the list. Overall, your function is trying to find if there is any common element(number) between all tuples.
A set is a python collection of hashable-types that has the special feature that no entity in the collection can repeat (the hash returned from it's __hash__ magic method, and thereby also the boolean return from the __eq__ method cannot be equal to any other entity in the list) It is used wherever a collection is required that can not have repeated entities.
It's hard to tell the intention of the snippet entirely without knowing the context of its use, especially since the values you have for l are all tuples within a container list. The intersection_update is a method of a set that returns a set from the original keeping only elements also found in the one that is passed as an argument. The zero-indexed key is fetching the first tuple from the list.
http://docs.python.org/library/sets.html

Categories