Search code examples
pythonpython-3.xpython-2.5python-collections

How can I port this code using collections.deque from Python 2.5 to 3.4?


How can you port this code from 2.5 to 3.4 version?

from __future__ import with_statement
from ..globals import addonPath
import os, time
import collections

class TailDeque(collections.deque):
    '''Implementation of deque with limited maxlen support for Python 2.5.'''
    def __init__(self, iterable=None, maxlen=20):
        super(TailDeque, self).__init__([])
        self.maxlen = maxlen
        if iterable is not None:
            self.extend(iterable)

    def extend(self, iterable):
        for item in iterable:
            self.append(item)

    def extendleft(self, iterable):
        for item in iterable:
            self.appendleft(item)

    def appendleft(self, item):
        if len(self) == self.maxlen:
            self.pop()
        super(TailDeque, self).appendleft(item)    

    def append(self, item):
        if len(self) == self.maxlen:
            self.popleft()
        super(TailDeque, self).append(item)

logPath = os.path.join( addonPath, "log.txt" )
logQueue = TailDeque()
def log(text):
    return
    logQueue.append(time.strftime("%H:%M:%S") + " - " + text)
    with open(logPath, "w") as fs:
        fs.write('\n'.join(logQueue))

Line 10: self.maxlen = maxlen

AttributeError: attribute 'maxlen' of 'collections.deque' objects is not writable


Solution

  • I think you need to replace these two lines:

    super(TailDeque, self).__init__([])
    self.maxlen = maxlen
    

    with:

    if sys.version_info <= (2, 5):
        super(TailDeque, self).__init__([])
        self.maxlen = maxlen
    else:
        super(TailDeque, self).__init__([], maxlen=maxlen)
    

    If you don’t need to maintain compatibility with Python 2.5, you can be a bit simpler:

    super(TailDeque, self).__init__([], maxlen=maxlen)
    


    Motivation

    In Python 2.5, the constructor for collections.deque only took a single argument, iterable:

    deque([iterable])

    so you had to set the maxlen after initialising the object.

    In Python 2.6, you were able to supply maxlen as an optional argument:

    collections.deque([iterable[, maxlen]])

    This has stayed the same into Python 3.4. I think that setting it as a constructor argument was the preferred approach from 2.6 onwards. They couldn’t take away your approach – setting the attribute directly – in the 2.x series, because they didn’t want to break backwards compatibility.

    With Python 3, there were no such concerns, and so using constructor arguments became the only approach you could use.


    Side note

    Rather than initialising with an empty list and then extending with the user-supplied utterable, why not pass that iterable to collections.deque directly? i.e.

    super(TailDeque, self).__init__(iterable, maxlen=maxlen)