String confusion


#5

Actually. Index of the last value is totally a sensible thing to hold on to now that I actually read the code…


#6
def reverse(text):
    word = ""
    letter_index_position = len(text) - 1
    while letter_index_position >= 0:
        word = word + text[letter_index_position]
        letter_index_position -= 1
    return word

All gucci now.


#7

I’d go with i haha

Also. To make things a bit difficult for you let me point out that each time you do addition there, you copy all of the previous string!

So, for example to reverse 'abcdefghij', ALL of these would get created:

j
ji
jih
jihg
jihgf
jihgfe
jihgfed
jihgfedc
jihgfedcb
jihgfedcba

By the triangle shape of that you can also tell how much work it is (length * length / 2)

It kind of should be a list. Because that allows appending.
And then join afterwards.


#8

I dont think this is right. Since the variable is reused this should not be an issue right ?

Also addition is not something you should worry about in loops i think.
After some testing i even want to say @kekpop his result is better.

Check for yourself:

import time

def reverse(text):
    word = ""
    letter_index_position = len(text) - 1
    while letter_index_position >= 0:
        word = word + text[letter_index_position]
        letter_index_position -= 1
    return word
	
	
	
def reverseTwo(text):
	result = []
	for i in range(len(text)-1, -1, -1):
		result.append(text[i])
	return "".join(str(x) for x in result)
	
def getRandomString(length):
	result = ''
	for i in range(length):
		result = result + 'a'
	return result

print(reverse("HELLO WORLD !!"))

print(reverseTwo("HELLO WORLD !!"))


# checking efficiency on redicualous large strings.
input = getRandomString(100000) # string with a bunch of 'a' characters

t0 = time.time()
reverse(input) # not printing result its just 'a's anyway
t1 = time.time()
print(t1-t0)  	# output --> 0.17 ish

t0 = time.time()
reverseTwo(input) # not printing result its just 'a's anyway
t1 = time.time()
print(t1-t0)	# output --> 0.28 ish

#9

variables aren’t memory


#10

I dont understand what you mean. If you overide your variable the value in the memory, if not used on some other place, will be overwritten.

in this thread i made an example for it that shows how it is overwritten.


#11

The testing goes that way because CPython does something here that isn’t part of the language itself. It is able to tell that NOBODY else knows about that value, and it can therefore modify it in-place.

If you run the same code in Jython and maybe pypy, you would see a very large difference


#12

What you show in that thread is that the id number is re-used. Not memory.
Id is guaranteed to be unique between currently existing objects. What happens there is that one of them goes out of existence, and a completely new value gets the same id.


#13

so only the last line would keep excisting right ? Isnt the rest just garbage collection ?
How would you test if the memory is still being used ? and how would you know what the values are for this memorie usage ?


#14

Yes the rest gets garbage collected. The problem is the work to create them.
If the string is 1 million characters long, then instead of 1 million amount of work, it’s 1 million * 1 million / 2 – this will be really really slow.

HOWEVER, yes, CPython will do this “right”
The problem is that 1) the code says to do the wrong thing 2) the wrong thing is what will happen in other python implementations

If only targetting CPython then yeah it’s a somewhat reasonable thing to do intentionally. I don’t know whether CPython promises to keep doing it in all their versions though. They might feel that they have to if there’s a lot of code relying on it.


#15
$ python biirrabench.py
!! DLROW OLLEH
!! DLROW OLLEH
0.019551515579223633
0.026768922805786133
$ pypy3 biirrabench.py
!! DLROW OLLEH
!! DLROW OLLEH
4.598165988922119
0.024868488311767578
$ jython biirrabench.py
!! DLROW OLLEH
!! DLROW OLLEH
2.59999990463
0.161999940872

#16

Oh and let me rewrite the code for the second version:

def reverseTwo(text):
	return "".join([text[i] for i in range(len(text)-1, -1, -1)])
$ python biirrabench.py 
!! DLROW OLLEH
!! DLROW OLLEH
0.021166086196899414
0.007839679718017578

#17

I wouldn’t write that either though.
I’d write: (well, without the function, redundant)

def reverseTwo(text):
	return text[::-1]
$ python biirrabench.py 
!! DLROW OLLEH
!! DLROW OLLEH
0.01616048812866211
0.0001289844512939453   <-- that's actually obscene, I wonder if python simply decides to not do it until later

#18

ah i guess your right. i haven’t made the string long enough to see correct results.

I’m not sure why you keep referring to CPython btw. all this code is normal python right ?

also could you explain how you get this sum out of the code ?


#19

I used your length! 100k is fine. Because 100k*100k is a lot, it definitely shows up in a measurement.

That’s the area of a triangle. (print out all the strings, get area, see my third post)
It’s also the number of characters that will be created in total.

The average length will be len/2, and it happens len times -> len * len / 2


#20

Look at my post where I ran different python implementations (cpython, pypy, jython)
cpython is the one from python.org, named so for being written in C


#21

I understand now thanks for explaining.


#22

What CPython does which is different from jython and pypy, is reference counting

When you make a variable refer to a value. That value gets its reference count increased. When your variable stops referring to the value, the count decreases. When the count reaches 0 (probably not 0, python itself may also have references to it), when python sees that the code no longer references it, then it deletes the value.

It’s by that same count that string is able to tell that nobody is looking. You can think of it as deleting the original and making a new one, except it doesn’t actually delete the old one, it slaps on another character and uses it as the new one. It’ll keep its old id number too, and that’s totally fine because in a sense it stopped existing, and then came back. (again, the guarantee of unique id’s is only between simultaneously existing values)

technically the id could have been changed, but cpython uses memory locations as the id, and it’s the same piece of memory so… – though it might also decide to create a new one and that would change the id. I don’t know. Just saying it can’t and shouldn’t be relied on, and would be really weird regardless.


#23
def reverseTwo(text):
	return text[::-1]

I have seen this one before, it’s what I use when I want to reverse my stuff. I only do not understand one thing, what is the process. Are those even indexes?


#24

It’s called slicing. The arguments are (start, stop, step), roughly the same as the range function.
Left out arguments are given defaults for beginning and end (reversed with negative step)

It’s like getting a substring, except for any sequence