I needed a deque
who's maxlen
can be set again after it has been initialized. So, since new-style classes in Python are treated as types, I decided to create a new class borrowing from deque
to accomplish this. My approach is to have an internal deque
as an attribute and when maxlen
is set, it replaces the internal deque
with a new one, initialized to the old contents and the new maxlen
.
I tried subclassing deque
but it's too crude, creating a deque
that's useless on top with the useful one internally. So I chose to simply have all of the wrapper class's attributes (except special ones) point to the internal deque
's. However, due to how new-style classes work, the special attributes have to be handled manually. Since all I want is to override maxlen
's setter, all of this seems inelegant and I'm wondering if there's a cleaner way of accomplishing this.
From what I've read here, it seems I could subclass this class in __new__
to skip overriding the special attributes, but that seems even more hairy than what I already wrote.
This is the result, stripped of extraneous comments (complete code here if you want something runnable, with tests):
# -*- coding: utf-8 -*-
from __future__ import print_function
from collections import deque
class ResizableDeque(object):
def __init__(self, *args, **kwargs):
self.internal = deque(*args, **kwargs)
skip_list = [
'maxlen'
] + [attr for attr in dir(deque) if attr.startswith('__') and
attr.endswith('__')]
for attr in dir(deque):
if attr not in skip_list:
setattr(self, attr, getattr(self.internal, attr))
@property
def maxlen(self):
return self.internal.maxlen
@maxlen.setter
def maxlen(self, value):
templist = list(self.internal)
self.internal = deque(templist, value)
def __str__(self):
return self.internal.__str__()
def __repr__(self):
return self.internal.__repr__()
def __getitem__(self, value):
return self.internal.__getitem__(value)
def __setitem__(self, index, value):
return self.internal.__setitem__(index, value)
# these have not been tested
def __copy__(self):
return self.internal.__copy__()
def __delitem__(self, index):
return self.internal.__delitem__(index)
def __iadd__(self, other):
return self.internal.__iadd__(other)
def __len__(self):
return self.internal.__len__()
# not sure if overriding __sizeof__ is wise this way
def __sizeof__(self):
return self.__sizeof__() + self.internal.__sizeof__()
# pretty sure this is ok
def __format__(self, spec):
return self.internal.__format__(spec)
__getattr__
or__getattribute__
magic methods to catch access to attributes and forward it to the wrapped object. \$\endgroup\$__init__
stuff gets copied from.internal
, but not updated wheninternal
changes on settingmaxlen
. \$\endgroup\$