The defaultdict class will automatically create my list when I access it
pool = collection.defaultdict(list)
The python style guide suggests using the form class_ rather then clas
It is also not clear why you are capturing the incoming arguments as variable.
This being a metaclass it is going to have consistent parameters
def __new__(class_, name, bases, classdict):
Since pool now automatically creates the list, we can just append to it
Getting rid of the variable arguments also makes this much clearer.
classdict['__del__'] = __del__
return type.__new__(class_, name, bases, classdict)
args and kwargs are often used as the names for variable parameters. I recommend using them to make code clearer
def __call__(class_, *args, **kwargs):
Thanks to the use of defaultdict above we can make this code quite a bit cleaner. Also, this code doesn't pretend its using a functional programming language. Your code created lists by adding them together, slicing, etc. That is not a really efficient or clear way to use python.
instances = Pool.pool[class_]
There is a subtle and dangerous problem here. When you create a new instance, you pass along your parameters.
However, if an instance is already created, you return that ignoring what the parameters were doing.
This means that you might get an object back which was created using different parameters then you just passed.
I haven't done anything to fix that here
print('Pool.pool is not empty: return an already allocated instance')
print('Pool.pool is empty, allocate new instance')
return type.__call__(class_, *args, **kwargs)
Your technique is to install a
__del__ method on the objects so that you can detect when they are no longer being used and keep them in your list for the next person who asks for them. the
__del__ method is invoked when the object is about to be deleted. You prevent the deletion by storing a reference to the object in your list. This is allowed but the python documentation indicates that it is not recommended.
__del__ has a number of gotchas. If an exception is caused while running the
__del__ method it will be ignored. Additionally, it will tend to cause objects in references cycles to not be collectable. If your code is ever run on Jython/IronPython then you can't be sure that
__del__ will be called in a timely manner. For these reasons I generally avoid use of
You are using a metaclass so the fact that the given object is pooled is hidden from the user. I don't really think this is a good idea. I think it is far better to be explict about something like pooling. You also lose flexibility doing it this way. You cannot create multiple pools, etc.
The interface that I would design for this would be:
pool = Pool(Foo, 1, 2, alpha = 5) # the pool gets the arguments that will be used to construct Foo
with pool.get() as f1:
# as long as I'm in the with block, I have f1, it'll be returned when I exit the block
with pool.get() as f2:
with pool.get() as f3:
f4 = pool.get()