The most pythonic way of going about this would probably be a list comprehension:
results = [b.get_a().do_something() for b in collection]
If you want to cache calls to B.get_a()
, you can use memoization. A simple way of doing memoization yourself could look like this:
cache = None
# ...
class B:
def get_a(self):
global cache
if cache is None:
cache = A()
return cache
If you want to use caching in multiple places, you'll need to cache results based on keys in order to distinguish them, and for convenience's sake write a decorator that you can simply wrap functions with whose results you want to cache.
A good example of this is found in Python Algorithms: Mastering Basic Algorithms in the Python Language (see this question). Modified for your case, to not use the function arguments but the function name as cache key, it would look like this:
from functools import wraps
def memoize(func):
cache = {}
key = func.__name__
@ wraps(func)
def wrap(*args):
if key not in cache:
cache[key] = func(*args)
return cache[key]
return wrap
class A:
def do_something(self):
return 1
class B:
@memoize
def get_a(self):
print "B.get_a() was called"
return A()
collection = [B(), B()]
results = [b.get_a().do_something() for b in collection]
print results
Output:
B.get_a() was called
[1, 1]