R
Robert Brewer
def warehouse(stock, factory=None):
"""warehouse(stock, factory=None) -> iavailable, iremainder.
Iterate over stock, yielding each value. Once the 'stock' sequence
is
exhausted, the factory function (or any callable, such as a class)
is
called to produce a new valid object upon each subsequent call to
next().
If factory is None, the class of the first item in the sequence is
used
as a constructor. If the factory function is not a bound method, it
does
not receive any arguments, so if your class has mandatory arguments
to
__init__, wrap the class in a function which can supply those.
A common use for warehouse is to reuse a set of existing objects,
often
because object creation and/or destruction is expensive. The
warehouse
function returns the second iterable ('iremainder') to allow
consumers to
"clean up" any items from the initial sequence which did not get
re-used.
For example, given a homogeneous iterable named 'i':
available, remainder = warehouse(i)
for thing in some_other_sequence:
thing.use(available.next())
for item in remainder:
item.close()
"""
if not hasattr(stock, 'next'):
stock = iter(stock)
def pull():
"""An inner generator from itertools.warehouse()."""
for item in stock:
yield item
if factory is None:
try:
local_factory = item.__class__
except NameError:
raise ValueError("Empty sequence and no factory
supplied.")
else:
local_factory = factory
while True:
yield local_factory()
return pull(), stock
What do you all think? I've been using a class-based variant of this in
production code (business app) for six months now, and have found it
extremely helpful. I saw a pointer to itertools today and figured a
function-based version might be nice to include in that module someday.
Robert Brewer
MIS
Amor Ministries
(e-mail address removed)
"""warehouse(stock, factory=None) -> iavailable, iremainder.
Iterate over stock, yielding each value. Once the 'stock' sequence
is
exhausted, the factory function (or any callable, such as a class)
is
called to produce a new valid object upon each subsequent call to
next().
If factory is None, the class of the first item in the sequence is
used
as a constructor. If the factory function is not a bound method, it
does
not receive any arguments, so if your class has mandatory arguments
to
__init__, wrap the class in a function which can supply those.
A common use for warehouse is to reuse a set of existing objects,
often
because object creation and/or destruction is expensive. The
warehouse
function returns the second iterable ('iremainder') to allow
consumers to
"clean up" any items from the initial sequence which did not get
re-used.
For example, given a homogeneous iterable named 'i':
available, remainder = warehouse(i)
for thing in some_other_sequence:
thing.use(available.next())
for item in remainder:
item.close()
"""
if not hasattr(stock, 'next'):
stock = iter(stock)
def pull():
"""An inner generator from itertools.warehouse()."""
for item in stock:
yield item
if factory is None:
try:
local_factory = item.__class__
except NameError:
raise ValueError("Empty sequence and no factory
supplied.")
else:
local_factory = factory
while True:
yield local_factory()
return pull(), stock
What do you all think? I've been using a class-based variant of this in
production code (business app) for six months now, and have found it
extremely helpful. I saw a pointer to itertools today and figured a
function-based version might be nice to include in that module someday.
Robert Brewer
MIS
Amor Ministries
(e-mail address removed)