3

Python uses names to reference objects. When we say a = b, a and b now refer to the same object, and if we change a, we will see the same change in b. For example:

a = [1, 2, 3]
b = a

a.append(4)

print(b)

will print [1, 2, 3, 4].

However, some operations do create new objects. For example:

a = 1
b = a

a = a + 1

print(b)

will print 1. Clearly the line a = a + 1 somehow creates a new object with a value of a + 1 and binds the name a to it. How does this work? What is the mechanism that creates a new object in this case?

This question is not a duplicate of this one, as I am asking specifically how the object creation happens in this case, whereas the other question was more generally about when names share objects.

Community
  • 1
  • 1
PProteus
  • 549
  • 1
  • 10
  • 23
  • 2
    Lists are mutable (use `copy` or slicing with `[:] `to copy them), integers are immutable (they are re-built every time, like strings) – Chris_Rands Jan 17 '17 at 15:39
  • 4
    Possible duplicate of [How does python assign values after assignment operator](http://stackoverflow.com/questions/34521078/how-does-python-assign-values-after-assignment-operator) – Josh Lee Jan 17 '17 at 15:40
  • Technically, I'm not sure that `a = a + 1` *creates* a new object in this particular case, as Python caches integers in the range [-5, 256]. Rather, I think that will assign a pre-made integer object from the cache to `a`. In other words, `a` will now point to a different object than `b`, but no object was created in that statement. Correct me if I'm wrong, though. – Tagc Jan 17 '17 at 15:44
  • It's similar, but the questions are different. My question asks specifically how and why a new object is created in a given operation. The old one asks more generally about object references. – PProteus Jan 17 '17 at 15:47
  • Tagc, I think you're right about small integers, so consider the same question for large integers. – PProteus Jan 17 '17 at 15:48

1 Answers1

2

I found the information I was looking for on the mechanics of object creation in Luciano Ramalho's book Fluent Python.

Ramalho explains that while __init__ is usually considered the "constructor", in fact, objects are created by calling the __new__ method. It is a class method, and it returns an instance of a class, which gets passed to __init__ as the first argument (conventionally "self"). Thus, __init__ is the initializer, not the constructor.

This can be illustrated with the following example:

class C(object):
    def __new__(cls):
        new_inst = object.__new__(cls)
        print new_inst.__dict__
        new_inst.var_1 = 1
        return new_inst

    def __init__(self):
        print self.__dict__
        self.var_2 = 2

a = C()             # Prints:
                        # {}
                        # {'var_1': 1}
print a.__dict__    # returns {'var_2': 2, 'var_1': 1}

b = C.__new__(C)    # Prints:
                        # {}
print b.__dict__    # returns {'var_1': 1}

b.__init__()        # Prints:
                        # {'var_2': 2, 'var_1': 1}
print b.__dict__    # returns {'var_2': 2, 'var_1': 1}

The line a = C() calls __new__ followed by __init__, as we can see from the printouts of __dict__. This can be broken into separate calls, as shown with the object b.

This question is also relevant.

Community
  • 1
  • 1
PProteus
  • 549
  • 1
  • 10
  • 23
  • 1
    Since you are the OP it is up to you to decide whether it is right or wrong, but I don't think you have really answered your own question. It still remains to be explained why `a = b` may create a new object in some cases (e.g. big integers) but not in other (e.g. lists). For example, is it possible to tweak `__new__` or the metaclass of a class to reproduce a "primitive-like" behaviour for custom classes? – jdehesa Jan 31 '17 at 14:54
  • You're right, it's probably a partial, answer. It does help me understand the "mechanics of object creation", which I referred to in the question, however, which was what I was most curious about. – PProteus Jan 31 '17 at 15:01