1

I've read this post about circular referencing in python, but I'm not 100% whether weakref is the way to go in my case.

So here is where I am.

I wrote a framework for file versionning. I have a File class that I manipulate to have information about local revision and the server revision.

It would looks like this (I intentionally inverted the classes declarations):

class File(object):
    def __init__(self, path):
        self.path = path
        self.db_object = db_query_file(path)
        self.local = _LocalVersion(self)
        self.latest = _LatestVersion(self)

class _Version(object):
    def __init__(self, file):
       self.file = file

    def size(): pass
    def checksum(): pass

class _LocalVersion(Version):
    def __init__(self, file):
        super(_LocalVersion, self).__init__(file)
        self.info = get_info_from_local(file.path)

    def size(): return local_size(self.file.path)
    def checksum(): return local_checksum(self.file.path)

class _LatestVersion(Version):
    def __init__(self, file):
        super(_LatestVersion, self).__init__(file)
        self.info = query_latest_info_from_db(file.db_object)

    def size(): return self.info.size
    def checksum(): return self.info.checksum

Now I suspect that none of my File objects will ever be garbage collected as they are referenced by their very internal organs, and thus will always have a positive ref count.

The instances of _Version have no purpose of existing when the File instance must be deleted, of course.

Would it be safe and relevant to define _Version as:

class _Version(object):
    def __init__(self, file):
        self.file = weakref.proxy(file)

Thanks for your comments, corrections and ideas!

Cheers O.

Community
  • 1
  • 1
Olivier H
  • 835
  • 2
  • 8
  • 26

1 Answers1

3

Now I suspect see that none of my File objects will ever be garbage collected as they are referenced by their very internal organs, and thus will always have a positive ref count.

CPython runs a garbage collector from time to time to break circular references. Your objects will be collected, albeit a little slower.

Would it be safe and relevant to define _Version as:

class _Version(object):
    def __init__(self, file):
        self.file = weakref.proxy(file)

It would be perfectly safe, yes. Unless you are running a long-running process and are planning to release a large number of File instances at a time, it may be overkill however. If there are a large number of circular references the garbage collector could impact overall performance if a lot of orphaned circular references are left around on a regular basis.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • Thanks for the hint. I did not know about that circular ref breaker. It may thus be unnecessary for me to use weak refs, as the users don't use more than a few thousand objects at a time. Do you know the impact on performance when using weak refs? – Olivier H Jun 13 '14 at 08:46
  • @OlivierH: not in detail; you can measure that with the `timeit` module for your specific use. It'll be fast, though; a `weakref.proxy()` does all its work in C code, and Python types have special provisions for weak references. – Martijn Pieters Jun 13 '14 at 10:24
  • Glad to have been of help! – Martijn Pieters Jun 20 '14 at 11:34