Are Python Variables Pointers? or Else, What Are They

Are Python variables pointers? Or else, what are they?

We call them references. They work like this

i = 5     # create int(5) instance, bind it to i
j = i # bind j to the same int as i
j = 3 # create int(3) instance, bind it to j
print i # i still bound to the int(5), j bound to the int(3)

Small ints are interned, but that isn't important to this explanation

i = [1,2,3]   # create the list instance, and bind it to i
j = i # bind j to the same list as i
i[0] = 5 # change the first item of i
print j # j is still bound to the same list as i

In Python, are all variables void pointers?

The correct explanation really is that: Python has names, other languages have variables. What this means is that Python's variables are recovered by looking up their name in a dict at runtime.

Although, I'll give you that in my early Python days I too found this explanation disappointing. What I would have liked at the time would have been examples of what this implies for the developper.

Variables are in a dict

In lower-level languages, a variable's name is thrown away and replaced by an address in memory by the compiler. This is not the case in Python, which allows you to access all variables with the vars builtin that returns the dict of the scope's variable.

This means you can read variables from that dict.

foo = 1
vars()['foo'] # 1

And that you can update and even declare a variable using this dict.

vars()['bar'] = 1
bar # 1

It also means you can list all variables in scope.

foo = 1
bar = 1
vars().keys() # ['__name__', '__doc__', ... , 'foo', 'bar'])

The NameError exception

In C, accessing a variable that has not been declared is a compile error. In Python, since variables' names are looked up in a dict, it is a runtime exception that can be caught like any exception.

try:
print(foo)
except NameError:
print('foo does not exist') # This is printed

There are no pointers

In Python, the whole mechanic of accessing a value by its position in memory is hidden from you. Your way to access a variable is by knowing its name.

In particular this means that you can delete a name and prevent all access whatsoever to its value.

foo = object()
del foo
# The above object is now completely out of reach

What the above does is remove the 'foo' key in the vars() dict.

Understanding pointers and merging lists in python

Every Python variable is a reference to a value; if you already understand how pointers work in C, then it might be useful to think of variables which reference mutable objects as working like C pointers. They aren't really the same thing, but a Python variable that references a ListNode acts a lot more like a C ListNode* than a C ListNode, so the pointer metaphor is a good conceptual starting point if that's the language you're coming from.

  1. dummy always points to the node that you created in the first line of the function, which is the same node that cur starts at. The first time you update cur.next, you are also updating dummy.next. cur is then reassigned to a new node, but the modification you made to dummy persists.

This Python code:

        cur = dummy = ListNode()
while list1 and list2:
if list1.val < list2.val:
cur.next = list1
list1, cur = list1.next, list1

is essentially the same as:

        ListNode* cur, dummy;
cur = dummy = new ListNode();
while (list1 && list2) {
if (list1->val < list2->val) {
cur->next = list1;
cur = list1;
list1 = list1->next;
}
}

  1. One is modifying the next attribute of the node that cur points to; the other is modifying cur itself to point at a new node.
                cur.next = list2
cur = cur.next

is the same as:

                cur->next = list2;
cur = cur->next;

For a more in-depth explanation of how exactly variables work in Python, read https://nedbatchelder.com/text/names.html

Python variables under the hood

  1. Not really, but close. A Python variable is a name that refers to an object. Full stop. Python doesn't define any semantics about how this is done.

  2. print takes an object as its argument. That object can be passed via a literal (print(3), print("foo"), print(True)), or via a reference (print(a)).

  3. id returns an integer identifier that is unique to that object for the lifetime of that object. What that integer is is also not defined by the language; it's up to the implementation to decide. It could just as easily be a serial number that starts with 0 and gets incremented every time a new object is created.

Any question about "under the hood" can only be answered by specifying which implementation of Python you are using, and that answer will not really be of any use in understanding what a particular piece of Python means, only in understanding how a particular implementation does it.

how python variable works?

What you're seeing is an optimization detail of CPython (the most common Python implementation, and the one you get if you download the language from python.org).

Since small integers are used so frequently, CPython always stores the numbers -5 through 256 in memory, and uses those stored integer objects whenever those numbers come up. This means that all instances of, say, 5 will have the same memory address.

>>> a = 5
>>> b = 5
>>> id(a) == id(b)
True
>>> c = 4
>>> id(a) == id(c)
False
>>> c += 1
>>> id(a) == id(c)
True

This won't be true for other integers or non-integer values, which are only created when needed:

>>> a = 300
>>> b = 300
>>> id(a) == id(b)
False

Pointers in Python?

There's no way you can do that changing only that line. You can do:

a = [1]
b = a
a[0] = 2
b[0]

That creates a list, assigns the reference to a, then b also, uses the a reference to set the first element to 2, then accesses using the b reference variable.



Related Topics



Leave a reply



Submit