0

I'm trying to understand what happens with assignment and the creation of new references to an object, or why I get a new created object when assigning.

I can't get my head on how Python and/or Sublime work here. I have this simple Sublime plugin:

import sublime
import sublime_plugin

class TestpythonCommand(sublime_plugin.TextCommand):
    def run(self, edit):
        view = self.view
        sel = view.sel()
        sel_zero = sel[0];
        sel_for = []
        for r in sel:
            sel_for.append(r)
        sel_gen = [r for r in view.sel()]

        print('SEL => ' + str(sel[0].a) +':' + str(sel[0].b) + ' ID: ' + str(id(sel[0])))
        print(str(id(sel[0])) + ' .. ' + str(id(sel[0])) + ' .. access A value: ' + str(sel[0].a) + ' .. ' + str(id(sel[0])))
        print('SEL[0] id is ' + str(id(sel[0])))
        print('SEL_ZERO => ' + str(sel_zero.a) +':' + str(sel_zero.b) + ' ID: ' + str(id(sel_zero)))
        print('SEL_FOR => ' + str(sel_for[0].a) +':' + str(sel_for[0].b) + ' ID: ' + str(id(sel_for[0])))
        print('SEL_GEN => ' + str(sel_gen[0].a) +':' + str(sel_gen[0].b) + ' ID: ' + str(id(sel_gen[0])))
        print('----- Test with self')
        print(id(sel[0]) == id(sel[0]))
        print(sel[0] is sel[0])
        print(sel[0] == sel[0])
        print('----- Test with list & generator function')
        print(sel[0] is sel_zero)
        print(sel[0] == sel_zero)
        print(sel[0] is sel_for[0])
        print(sel[0] == sel_for[0])
        print(sel[0] is sel_gen[0])
        print(sel[0] == sel_gen[0])

Executing this returns:

SEL => 657:657 ID: 4378999048
4378998328 .. 4378998328 .. access A value: 657 .. 4378998328
SEL[0] id is 4378998328
SEL_ZERO => 657:657 ID: 4379000488
SEL_FOR => 657:657 ID: 4378996816
SEL_GEN => 657:657 ID: 4378998760
----- Test with self
True
False
True
----- Test with list & generator function
False
True
False
True
False
True

Now, too many things don't make sense to me here:

  1. First print shows sel[0] id to be 4378999048, but printing it again gives another id (4378998328)
  2. Third print does the same; looks the id printed in the first line is lost/changed/unused.
  3. First "Test with self" print makes sense (comparison of id strings is True); but I can't get the sense of the second print, using is (why sel[0] is not sel[0]?).

I am trying to understand how stuff works here. Specifically, the purpose is to understand why I get new objects (instead of having a new reference to the same object) when using the generator-expression with for.

I use SublimeText3 and Python 2.7.10.

EDIT: I'd be interested in the best practice for checking reference equality, without using is (that seems to be inconsistent, depending on implementation and caching).

Kamafeather
  • 8,663
  • 14
  • 69
  • 99
  • 1
    There is no inconsistency. The two objects are the same object or they are not. And `is` checks it. What you shouldn't do is relying in two references to immutables pointing an object with the same value, to be the same object. It can be the same or be different because of Python internal optimization, and because it does NOT matter (you can't change them). – progmatico Sep 24 '18 at 13:51
  • @progmatico with *"relying in two references to immutables pointing an object with the same value, to be the same object"* do you refer to the `==` comparisons? In that case, I'm aware that the identity is just in the value (that's actually my initial problem; I need to ensure the objects to be the same, rather than another object with same value). I still don't get why `sel[0] is sel[0]` returns `False`. – Kamafeather Sep 24 '18 at 19:51
  • Out of curiosity, is this question the result of something you were trying to do in a Sublime plugin that wasn't working the way you intended? – OdatNurd Sep 24 '18 at 20:07
  • Yes: get selection *Ranges*, process view based on them, keep selection updated according to view changes. A *View*'s (unique) *Selection* has multiple *Range*(s); *Range*'s buffer pointers are updated according to what's performed on parent *View*. But, from what I deduce (not knowing Sublime internals), putting `view.sel()` items into a list takes them out of context (creating new *Range* objects, rather than referencing the ones into the *View*'s *Selection*; **hence my tests with `is` above**); if `view.replace()` uses these detached regions then the *View*'s *Selection* won't update. – Kamafeather Sep 25 '18 at 15:19

2 Answers2

1

Printing out the id() of an expression at multiple points in time proves ABSOLUTELY NOTHING. If the first object is no longer referenced, a second object could possibly be allocated at the same address, and therefore have the same id; under certain circumstances, this is actually a fairly likely outcome. Both objects have to exist at the same time for their ids to be meaningfully compared. For example,

a = sel[0]
b = sel[0]
print(id(a), id(b))

would be a valid test for whether sel's indexing operation is returning the same object each time, or creating one from scratch.

jasonharper
  • 9,450
  • 2
  • 18
  • 42
0

Look at this example:

from collections import UserList

class MyList(UserList):

    def __init__(self):
        self.gen = iter([10,20,30])

    def __getitem__(self, index):
        return next(self.gen)

# This is what you expect:
a = [10,20,30]
print(a[0] is a[0]) # True

# And this looks surprising at first:
b = MyList()
print(b[0] is b[0]) # False

# Without knowing MyList internals, I
# cannot predict what I am getting on
# each access (except maybe by trusting
# available documentation)

# I don't know about sublime.
# In my other comment I just wanted
# to emphasize that operator `is`
# works reliably.

# You don't know if a is b or not:
a = 1
b = 1
# a is b can be True or False.
# But as they hold the same immutable value
# it really doesn't matter. Things will work
# the same with either a or b.

# to find out about identity, just test with 
# a is b
progmatico
  • 4,714
  • 1
  • 16
  • 27