3

If a class is defined in interpreter environment:

class C(object):
    def __init__(self, val):
        self.x = val

Then instantiated without names:

>>> C(1)
>>> C(2)
>>> 

Then we can use underscore _ to refer to C(2), so here is my question:

  • Since the underscore '_' refer to C(2), can we say the reference counter for C(2) is still 1? So the python gc will not free the memory taken by C(2)?
  • As far as I know, after these C(2) is executed, no names will refer to C(1), so can I say as soon as C(2) is executed, C(1)'s memory will be freed by python gc?

These are actually 4 questions, one bold font to one.

gc: short for garbage collection

EDIT

Let me make my first question more clear by commenting directly into the codes.

>>> C(1) # Press Enter Key and run
>>> 
>>> At Here, what is the exact reference count for the previous anonymous object "C(1)"? 
>>> And how to prove?
>>> 
>>> C(2) # Press Enter Key and run
>>> 
>>> At Here, what is the exact reference count for the previous anonymous object "C(1)"?
>>> And how to prove?
Charles
  • 115
  • 1
  • 8
  • 2
    Yes, essentially. You can explore this empirically using `sys.getrefcount` – juanpa.arrivillaga Nov 07 '17 at 05:36
  • @juanpa.arrivillaga If I run sys.getrefcount(C(2)) again, I will expect the result will be 2 because the last _ underscore is referencing it. But the result is 1. So I think your explanation is not convincing enough. – Charles Nov 07 '17 at 06:06
  • `sys.getrefcount(C(2)) ` creates an entirely new `C` object, passes it to refcount, and *never binds it to a name*. There is never more than one. – juanpa.arrivillaga Nov 07 '17 at 06:59
  • @juanpa.arrivillaga How can I make sure C(2) still exists in memory except using underscore? I mean, is there a way to check the **last** C(2) still holds a refcount? – Charles Nov 07 '17 at 07:10
  • There are *two* `C` objects with `val == 2`. Unless you bind them to a name, then **no**, there will only ever be `1` when you get it's refcount. All the REPL does is bind the result of evaluating the last expression to `_`. You can instead do `x = C(2)` then `x` then `sys.refcount(x)` – juanpa.arrivillaga Nov 07 '17 at 07:21
  • 1
    @juanpa.arrivillaga I think I didn't explain my question clear. I modified my question to make it more clear. – Charles Nov 07 '17 at 07:43

2 Answers2

2

@allen, thank you so much for your answer.

Based on your guess, I made the following code:

In [3]: {'a': 1}
Out[3]: {'a': 1}

In [4]: C(1)
   ...: print(_)
   ...: print(type(_))
   ...: print(number_of_instances(C))
   ...:
{'a': 1}
<class 'dict'>
0

In [5]:

So the _ underscore is only used for storing the value of last expression in interpreter of "Single Step Mode", not for "Continuous Mode".

This might be a common mistake made by beginners.

Anyway, thank you so much for your answer!

Charles
  • 115
  • 1
  • 8
  • Thank you! I have a related question, maybe you'll know the answer https://stackoverflow.com/q/63222197/854477 – int_ua Aug 03 '20 at 00:24
1

C(1) or C(2) as last line of the interpreter behaves differently when they are in the middle or to the up of the code.

If C(1) is at the last line, python interpreter will store it as <__main__.C object at 0x00000000********>, so actually it will have a name attached to it. If you check number_of_instances(C), the result will be 1.

If C(1) is not at the last line, this temporary anonymous object is just destroyed and disappeared.

Check the following testing codes.

You can use number_of_instances to show if there is any C object resides in memory.

import gc

def name_of_instances(cls):
    return [obj for obj in gc.get_objects() if isinstance(obj, cls)]

def number_of_instances(cls):
    return len([obj for obj in gc.get_objects() if isinstance(obj, cls)])

1.anonymous object not at last line

In [12]: C(1)
    ...: C(2)
    ...: print(number_of_instances(C))
    ...:
0

In [13]:

2.anonymous object at last line

In [6]: C(1)
Out[6]: <__main__.C at 0x6a97ba8>

In [7]: print(number_of_instances(C))
   ...: print(name_of_instances(C))
   ...:
1
[<__main__.C object at 0x0000000006A97BA8>]

In [8]: C(2)
Out[8]: <__main__.C at 0x6a9b518>

In [9]: print(number_of_instances(C))
   ...: print(name_of_instances(C))
   ...:
2
[<__main__.C object at 0x0000000006A97BA8>, <__main__.C object at 0x0000000006A9B518>]

3.underscore _ will remember C(3) if it is the last line

In [13]: C(3)
Out[13]: <__main__.C at 0x6aa06d8>

In [14]: type(_)
Out[14]: __main__.C

But in this case, the reference counter never counts reference from _, it only counts <__main__.C object at 0x0000000006AA06D8> which you didn't observe.

A guess here: _ is not in gc.garbage list. If you run C(1), print(number_of_instances(C)) successively, number_of_instances will not check into _ which may be storing the previous C(1)

See: sys.getrefcount continuation

allen He
  • 51
  • 2