Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How does Python's re-declaration of variables work internally?

I’m fairly new to Python so this might seem like a trivial question to some. But I’m curious about how Python works internally when you bind a new object to a variable, referring to the previous object bound to the same variable name. Please see the code below as an example – I understand that python breaks the bond with the original object ‘hello’, bind it to the new object, but what is the sequence of events here? how does python break the bond with the original object but also refer to it?

greeting = 'hello'
greeting = f'y{greeting[1:len(greeting)]}' 

In addition to the explanation, I would also very much appreciate some contexts. I understand that strings are immutable but what about other types like floats and integers?
Does it matter whether I understand how python operates internally? Also, where would be a good place to learn more about how Python works internally if it does?

Hope I’m being clear with my questions.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

An explanation through the medium of the disassembly:

>>> dis.dis('''greeting = 'hello'
... greeting = f'y{greeting[1:len(greeting)]}'
... ''')
  1           0 LOAD_CONST               0 ('hello')
              2 STORE_NAME               0 (greeting)

  2           4 LOAD_CONST               1 ('y')
              6 LOAD_NAME                0 (greeting)
              8 LOAD_CONST               2 (1)
             10 LOAD_NAME                1 (len)
             12 LOAD_NAME                0 (greeting)
             14 CALL_FUNCTION            1
             16 BUILD_SLICE              2
             18 BINARY_SUBSCR
             20 FORMAT_VALUE             0
             22 BUILD_STRING             2
             24 STORE_NAME               0 (greeting)
             26 LOAD_CONST               3 (None)
             28 RETURN_VALUE

The number on the far left indicates where the bytecode for a particular line begins. Line 1 is pretty self-explanatory, so I’ll explain line 2.

As you might notice, your f-string doesn’t survive compilation; it becomes a bunch of raw opcodes mixing the loading of constant segments with the evaluation of formatting placeholders, eventually leading to the stack being topped by all the fragments that will make up the final string. When they’re all on the stack, it then puts all the fragments together at the end with BUILD_STRING 2 (which says "Take the top two values off the stack and combine them into a single string").

greeting is just a name holding a binding. It doesn’t actually hold a value, just a reference to whatever object it’s currently bound to. And the original reference is pushed onto the stack (with LOAD_NAME) entirely before the STORE_NAME that pops the top of the stack and rebinds greeting.

In short, the reason it works is that the value of greeting is no longer needed by the time it’s replaced; it’s used to make the new string, then discarded in favor of the new string.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading