C Pointer arithmetic in Python - python

I'm trying to convert a simple C program into Python but as I don't know anything about C and a little about Python its just difficult for me..
I'm stuck at C pointers.
There is a function that takes an unsigned long int pointer and adds its values to some variables within a while-loop:
uint32_t somename(const uint32_t *z) {
while(....) {
a += z[0]
b += z[1]
c += z[2]
z += 3
}
}
Can someone please tell me how to accomplish the same thing in python?
(The part that I didn't understand at all is " z += 3 ")
I'm aware that there aren't pointers in python. (at least not like C) But the problem is that I don't know what C pointers exactly do and therefor can't make this happen in python.

A similar code snippet in Python might be:
def somename(z):
i = 0
while (....):
a += z[i]
b += z[i+1]
c += z[i+2]
i += 3
In C, z works sort of like an array index, except it starts at whatever the address of the start of the array is, rather than starting at 0. There is no analogous concept in Python, so you need to use a list index explicitly.
Whatever is inside (....) will need modification too. I'll leave that as an exercise for you, since it's unspecified in the question.

What z += 3 means is basically advance the pointer 3 elements down. Say you have a pointer to an array in C called lst which contains [1, 2, 3, 4]. The pointer lst points to the first element such that *lst is equivalent to lst[0]. Furthermore, *(lst+1) is equivalent to lst[1].

Assuming z is passed as a list (in the corresponding python code). The z += 3 can be translated to del z[:3] which moves the element 3 to 0.
However in python, you need to copy the array before doing that, because with the del-statement, the array gets modified.
In C you are able to access the elements before the pointed index through negative indices. This can be done with an "invisible" offset nested in a class. This offset is always added onto the index when the list is accessed.
The following class demonstrates the behavior.
class pointer_like:
def __init__(self, lst):
self.lst = lst; self.offset = 0
# self[index]
def __getitem__(self, index):
return self.lst[self.offset + index]
# self += offset
def __iadd__(self, offset):
self.offset += offset
# other member functions...
# as your example above
def somename(z):
z = pointer_like(z)
while (....):
a += z[0]
b += z[1]
c += z[2]
z += 3
>>> # other example
>>> z = pointer_like([0, 1, 2, 3, 4, 5])
>>> z[0]
0
>>> z += 3
>>> z[0]
3
>>>
>>> # with normal python lists, this would mean third last element
>>> z[-3]
0
>>> z += -5
>>> z[2]
0
>>>
>>> # this is special, because z.offset is negative (-2),
>>> # when a list item is accessed through a negative index,
>>> # it is counted from the end of the array in python.
>>> # In this case, it is -2, so the second last is accessed
>>> # In C this would cause undefined behavor, on most
>>> # platforms this causes an access violation
>>> z[0]
4
Note that pyhon also has a += operator for lists, but this allows to append another list at the end.

Related

Changing variable values in for loop?

I'm confused about how variables modified in part of a for loop behave outside the loop. Encountered this problem when doing a more complicated analysis but realised it's a basic for loop issue, easily shown with a toy example:
x, y, z = 1, 2, 3
for i in [x, y, z]:
i += 10
print(i)
# prints 11
# prints 12
# prints 13
print(x, y, z)
# prints 1 2 3
I would've expected the change to each iterated-over variable in the loop to stick outside of the loop, but evidently this isn't the case. I gather it's probably something about variable scope? Could someone explain how this works?
Actually you don't even need a for loop to showcase this what you call an issue but is actually not.
Take this simpler example:
x = 1
i = x
i += 10
print(x)
print(i)
Ofcourse x is not modified because it holds an immutable value of 1.
Here are immutable types in Python:
all primitive types: int, float, bool
plus tuple and str
Immutability means no shared reference.
So that when you have:
x = 1
y = 1
doesn't mean that x and y are referring to the same exact value 1 but instead each of the two variables have their "duplicate" instance of the same value. So that changing x doesn't affect y at all.
The same way, when you have:
x = 1
i = x
this is going to create a "brand new value of 1" and assign it to i, so that modifying i doesn't affect variable x at all.
But now, to get the behavior you want you can do something like:
x, y, z = 1, 2, 3
l = [x, y, z]
for i in range(len(l)):
l[i] += 10
x, y, z = l
Or if you really really want to be a little bit quirky, you can do:
x, y, z = 1, 2, 3
for var in locals().keys():
if var in ['x', 'y', 'z']:
locals()[var] += 10
But keep in mind that it is a good design decision from the creators of the language to keep certain types immutable, and so you should work with it instead and completely avoid using locals() as above or something else unnatural.
Actually it is not related to scopes.
Here you are iterating using the value i and increasing only i value, not any of x,y or z variable. So x,y and z remain unchnaged.
To change, use like this:
b = {'x': 1,'y': 2, ,'z': 3}
for m in b.keys():
b[m] += 10
The thing is that i variable is like a "temporary" variable in the for statement. So you are assigning i to a value of the array in each iteration. Look at the next example:
array = [1, 2, 3]
for i in array:
i += 10 #here we are modifying the "temporary" variable
print(array) #prints 1 2 3
index = 0
for i in array:
array[index] += 10 #here we are modifying the array
index += 1
print(array) #prints 11 12 13

My python recursive function won't return and exceeds maximum recursive depth

I simply do not understand why this is not returning the value and stopping the recursion. I have tried everything but it seems to just keep on going no matter what I do. I am trying to get the program to get the loop to compare the first two values of the list if they are the same return that it was the first value. If they were not, add the first and second values of each list and compare, etc etc until it reaches the end of the list. If the sum of the values in each list never equal each other at any point then return 0.
It is supposed to take three inputs:
A single integer defining the length of the next two inputs
First set of input data
Second set of input data
Ex input
3
1 3 3
2 2 2
It should output a single number. In the case of the example data, it should output 2 because the sum of the lists equalled at the second value.
N = int(input())
s1 = input().split()
s2 = input().split()
count = 0
def func1(x,y):
if x == y:
return(count)
elif (N - 1) == count:
return(0)
else:
count + 1
return(func1(x + int(s1[count]), y + int(s2[count])))
days = func1(int(s1[0]),int(s2[0]))
print(days)
I am sorry in advance if I really messed up the formatting or made some dumb mistake, I am pretty new to programming and I have never posted on here before. Thanks in advance :)
The problem is that you never actually update the variable count. However, just writing:
count += 1
is not going to work either without declaring the variable global:
def func1(x, y):
global count
....
That said, global variables increase code complexity and break re-enterability, i.e. the same function can no longer be called twice, not to mention about concurrency. A much cleaner way is to make count a function argument, it will look like this (the code not tested and is here for illustration only):
N = int(input())
s1 = [int(c) for c in input().split()]
s2 = [int(c) for c in input().split()]
def func1(x, y, count=0):
if x == y:
return count
elif count == N - 1:
return 0
else:
return(func1(x + s1[count], y + s2[count]), count + 1)
days = func1(int(s1[0]),int(s2[0]))
print(days)
To answer "How would you go about solving this problem then" – If I understood the problem correctly, the aim is to find the index where the "running total" of the two lists is the same. If so,
def func1(s1, s2):
total_a = 0
total_b = 0
for i, (a, b) in enumerate(zip(s1, s2)):
total_a += a
total_b += b
if total_a == total_b:
return i
return 0
print(func1([1, 3, 3], [2, 2, 2]))
does the trick. (I've elided the input bits here – this function just works with two lists of integers.)

Multiply odd indices by 2?

So I'm writing a function that is going to multiply each number at an odd index in a list by 2. I'm stuck though, as I really don't know how to approach it.
This is my code.
def produkt(pnr):
for i in pnr:
if i % 2 != 0:
i = i * 2
return pnr
If I, for example, type produkt([1,2,3]) I get [1,2,3] back but I would want it to be [2,2,6].
note that modifying i in your example does not change the value from the input list (integers are immutable). And you're also mixing up the values with their position.
Also, since indices start at 0 in python, you got it the wrong way.
In those cases, a simple list comprehension with a ternary expression will do, using enumerate to be able to get hold of the indices (making it start at 1 to match your case, you can adjust at will):
[p*2 if i%2 else p for i,p in enumerate(pnr,1)]
(note if i%2 is shorter that if i%2 != 0)
using list comprehensions:
multiply odd numbers by 2:
[x*2 if x%2 else x for x in pnr]
After clarification of question wording:
multiply numbers at odd indices by 2:
[x*2 if i%2 else x for i,x in enumerate(pnr)]
Consider using list comprehensions:
def produkt(pnr):
return [k * 2 if k % 2 else k for k in pnr]
Doing i = i * 2 you just override a local variable.
UPDATE (question was changed):
def produkt(pnr):
return [k * 2 if i % 2 else k for i, k in enumerate(pnr, 1)]
You can get the indices using enumerate, however that starts by default with index 0 (not 1) but it accepts a start argument to override that default.
The problem with your approach is that you don't change the actual list contents, you just assign a different value to the name i (which represented a list element until you assigned a different value to it with i = i*2). If you want it to work in-place you would need to modify the list itself: e.g. pnr[idx] *= 2 or pnr[idx] = pnr[idx] * 2.
However, it's generally easier to just create a new list instead of modifying an existing one.
For example:
def produkt(pnr):
newpnr = [] # create a new list
for idx, value in enumerate(pnr, 1):
# If you're testing for not-zero you can omit the "!=0" because every
# non-zero number is "truthy".
if idx % 2:
newpnr.append(value * 2) # append to the new list
else:
newpnr.append(value) # append to the new list
return newpnr # return the new list
>>> produkt([1,2,3])
[2, 2, 6]
Or even better: use a generator function instead of using all these appends:
def produkt(pnr):
for idx, value in enumerate(pnr, 1):
if idx % 2:
yield value * 2
else:
yield value
>>> list(produkt([1,2,3])) # generators should be consumed, for example by "list"
[2, 2, 6]
Of course you could also just use a list comprehension:
def produkt(pnr):
return [value * 2 if idx % 2 else value for idx, value in enumerate(pnr, 1)]
>>> produkt([1,2,3])
[2, 2, 6]
Try this:
def produkt(pnr):
return [ 2*x if i % 2 == 0 else x for i, x in enumerate(pnr)]
It will double every element in your list with an odd index.
>>> produkt([1,2,3])
[2, 2, 6]
Your code does not work, as i is no reference to the value inside the list, but just its value.
You have to store the new value in the list again.
def produkt(pnr):
for i in range(len(pnr)):
if pnr[i] % != 0:
pnr[i] *= 2
return pnr
or use this more convenient solution:
def produkt(pnr):
return [x * 2 if x % 2==0 else x for x in pnr]
Edit: As the question has been changed (completely) you should use this code:
def produkt(pnr):
return [x * 2 if ind % 2 else x for ind, x in enumerate(pnr)]
The first examples multiply each odd index by 2 and the former code multiplies the numbers at odd indices by 2.
Your problem is that i is a copy of the values in the pnr list, not the value in the list itself. So, you are not changing the list when doing i = i * 2.
The existing answers are already good and show the idiomatic way to achieve your goal. However, here is the minimum change to make it work as expected for learning purpose.
produkt(pnr):
new_pnr = list(pnr)
for ix in len(new_pnr):
if new_pnr[ix] % 2 != 0:
new_pnr[ix] *= 2
return new_pnr
Without new_pnr you'd be changing the list in place and then you wouldn't need to return it.

What does this construct do? [duplicate]

This question already has answers here:
Is there a standardized method to swap two variables in Python?
(8 answers)
Closed 6 years ago.
Example
num = [0,3,5,3,0,0,9,8]
Output should be
[3,5,3,9,8,0,0,0]
The solution to this in Python is
def moveZeroes(self, nums):
zero, cur = -1, 0
while cur < len(nums):
if nums[cur] != 0:
# update zero index when current is not zero
zero += 1
nums[cur], nums[zero] = nums[zero], nums[cur]
cur += 1
My question is I have seen similar statement like this a lot
nums[cur], nums[zero] = nums[zero], nums[cur]
What is this statement in particular doing?
The idiom
>>> a, b = b, a
swaps the values hold in a and b in one step so that a now points to the value that b used to point to, et vice versa:
>>> a, b = 1, 2
>>> a
1
>>> b
2
>>> a, b = b, a
>>> a
2
>>> b
1
Technically, the right-hand side creates a throwaway tuple, and the left-hand side is a tuple-unpacking assignment.
nums[cur], nums[zero] = nums[zero], nums[cur]
then means "swap the elements at index zero and at index cur.
This code nums[cur], nums[zero] = nums[zero], nums[cur] is swapping two values in the nums array. It is the same as if you had written:
temp = nums[cur]
nums[cur] = nums[zero]
nums[zero] = temp
When you use commas on both sides of the = assignment operator, Python essentially makes all of the assignments at once, so you don't need a temp variable.
It is swapping the values.
a, b = b, a
Now a has the value of b, and b has the value of a
This is Python's tuple packing and unpacking feature.
It's functionally identical to
temp = nums[cur]
nums[cur] = nums[zero]
nums[zero] = temp
but more efficient to the computer and more readable to programmers.
Further reading: https://stackoverflow.com/a/14836456/5399734
It's a variable swap, Python-style. It constructs a tuple of two values, the values at zero and cur, then unpacks that tuple and assigns the values to the indices at cur and zero; by reversing the indices assigned to, it swaps the values.
Note that the code could be simplified dramatically (though possibly at the expense of running slightly slower) by repurposing the key argument of the sort method to let Python do the work at the C layer:
def moveZeroes(self, nums):
nums.sort(key=lambda x: x == 0)
# Or more efficiently but obscurely:
# nums.sort(key=(0).__eq__)
# Or with an operator import to get speed with less obscurity:
# nums.sort(key=operator.not_)
Since Python's TimSort algorithm is stable, this preserves the order for all the non-zero values while moving the zeroes to the end.
It is first evaluating both of the values on the right, then it is substituting them to the matching slots on the left. So basically:
a, b = b, a
is like:
c = b
d = a
a = c
b = d
It is particularly useful to swap values or perform some operations on them without creating additional variables.

about iterators in python [duplicate]

This question already has answers here:
How to re-assign items in a list in Python?
(4 answers)
Closed 9 years ago.
If I have the following list:
a = [1, 2, 3]
And I run the following code:
for x in a:
x += 1
It seems that this does not change the list a.
However, if I do the following:
for i in range(0, len(a)):
a[i] += 1
This will modify the content of 'a'.
So I guess x and a[i] are referring to elements of a in a different way. What exactly is causing the difference? How are they each referring to elements of a?
When you iterate over a list, each element is yielded, in turn. However, there are different kinds of objects. mutable and immutable. When you do something like:
a += 1
with an immutable object, it translates roughly to:
a = a + 1
Now in this case, you take the object reference by a, add 1 to it to create a new object. Then you assign that new object the name a. Notice how if we do this while iterating, we don't touch the list at all -- We only keep creating new objects and assigning them to the name a.
This is different for a mutable object. Then a += 1 actually changes the object in place. So, the list will see the change because the object that it is holding has changed (mutated). (With the immutable object the object contained in the list wasn't changed because it couldn't be). See this question for more info.
This also makes it a little more clear what's happening when you're iterating by indices. you construct a new integer and you put it in the list (forgetting whatever was in that slot before).
When you say,
for x in [1,2,3]:
x+=1
You are saying, temporarily save x as a variable, and add one to that temporary save. When you get to the next iteration, the garbage man destroys that variable because it was temporary. x is not the spot in the list. It is the value of that spot in the list.
Edit: when I say that it gets deleted, I was not being clear with my words. What happens is that each time through the loop, x is replaced with another value, and so what happened before goes away (unless you did something else with it). With the operations you are using, though, you are not changing the values of any elements in the list. My bad for the confusion.
When you do it the other way,
for x in range(len(lst)):
lst[x] += 1
Then you are talking about the list's values. x is the index of the variable, and can therefore alter the value of the list's value at that spot.
The concept that matters here is the idea of referencing. In Python, variables are references to objects that sit somewhere in memory. Let's use the an arrow → to indicate a reference. Variable → Object. Variable on the left, object on the right.
The array can be visualized as three variables that reference three integer objects.
a[0] → int(1)
a[1] → int(2)
a[2] → int(3)
Now, integer objects are immutable. They can't be changed. When you change an integer variable you're not changing the object the variable refers to. You can't, because ints are immutable. What you can do is make the variable reference a different object.
Direct update
Let's look at the second loop first since it's simpler. What happens if you update the array directly?
for i in range(0, len(a)):
a[i] += 1
First let's unroll the loop:
a[0] += 1
a[1] += 1
a[2] += 1
For integers, a[0] += 1 is equivalent to a[0] = a[0] + 1. First, Python evaluates a[0] + 1 and gets the result int(2). Then it changes a[0] to reference int(2). The second and third statements are evaluated similarly.
a = [1, 2, 3] # a[0] → int(1)
# a[1] → int(2)
# a[2] → int(3)
a[0] += 1 # a[0] → int(2)
a[1] += 1 # a[1] → int(3)
a[2] += 1 # a[2] → int(4)
Indirect update
And what about what I'll call "indirect" updating?
for x in a:
x += 1
Unrolling the loop yields this equivalent series of statements:
x = a[0]
x += 1
x = a[1]
x += 1
x = a[2]
x += 1
What happens at each step, and why isn't the array changed?
x = a[0]
This makes x reference whatever object a[0] references. Both a[0] and x reference the same int(1) object, but x isn't directly connected to a[0]. It refers to whatever a[0] refers to, not to a[0] itself.
x += 1
This changes what x refers to. It has no effect on a[0].
The same thing happens for the second and third assignments. The result is that x is continually changed while the elements of a are merely read from but never modified. And so when the loop terminates a is unchanged.
a = [1, 2, 3] # a[0] → int(1)
# a[1] → int(2)
# a[2] → int(3)
x = a[0] # x → int(1)
x += 1 # x → int(2)
x = a[1] # x → int(2)
x += 1 # x → int(3)
x = a[2] # x → int(3)
x += 1 # x → int(4)
Think of it as in your first loop, x is just a substitute for every element in a. It's not the actual element in a (although by id() it is because they both reference the same object). When you're doing x += 1, you're just changing the value of x and not the value in the list.
In your second for-loop, you're actually modifying the list by doing a[i] += 1.

Categories