Reputation: 125
Is there a way to get a list or return all the instances of a class within a class in python? I've already done some research into it and all the answers that I've seen assume the instances are global variables, not part of an existing class.
For example, can I find all instances of Bar
that are instantiated within the class Foo
below?
class Foo:
def __init__(self):
self.mymsg1 = Bar('John Doe')
self.mymsg2 = Bar('Jane Doe')
self.somenumber = 42
self.somewords = 'hello world'
class Bar:
def __init__(self, name):
self.hellomsg = 'hello ' + name
I want to be able to get mymsg1
and mymsg2
because they are Bar
objects, but I don't want any of the other attributes or methods.
Upvotes: 3
Views: 130
Reputation: 21
This way you could filter whatever the class you pass by argument, and the function returns an array of that class objects.
class Foo:
def __init__(self):
self.mymsg1 = Bar('John Doe')
self.mymsg2 = Bar('Jane Doe')
self.somenumber = 42
self.somewords = 'hello world'
def filter_class(self, _class):
return [i[1] for i in (self.__dict__).items() if isinstance(i[1],_class)]
class Bar:
def __init__(self, name):
self.hellomsg = 'hello ' + name
Upvotes: 1
Reputation: 986
You can use class variable very easily:
class Foo:
def __init__(self):
self.mymsg1 = Bar('John Doe')
self.mymsg2 = Bar('Jane Doe')
self.somenumber = 42
self.somewords = 'hello world'
class Bar:
_instances = []
def __init__(self, name):
Bar._instances.append(self)
self.hellomsg = 'hello ' + name
>>> f = Foo()
>>> print('first:', Bar._instances[0].hellomsg,
... ', second:' ,Bar._instances[1].hellomsg)
first: hello John Doe , second: hello Jane Doe
For partitioning the Bar instances by instantiator, one can do this:
from collections import defaultdict
class Foo:
def __init__(self):
self.mymsg1 = Bar('John Doe', self)
self.mymsg2 = Bar('Jane Doe', self)
self.somenumber = 42
self.somewords = 'hello world'
class Bar:
_instances = defaultdict(list)
def __init__(self, name, instantiator):
Bar._instances[instantiator].append(self)
self.hellomsg = 'hello ' + name
>>> f, ff = Foo(), Foo()
>>> print('first:', Bar._instances[f][0].hellomsg,
... ', second:' ,Bar._instances[ff][1].hellomsg)
first: hello John Doe , second: hello Jane Doe
Upvotes: 2
Reputation: 27201
The simplest and most effective method is to create an appropriate data structure and avoid doing Python magic. However, if you have a degree in serpentine magic, I have listed various methods of advanced wizardry below.
__dict__
class Foo:
def __init__(self):
self.bar1 = Bar()
self.bar2 = Bar()
def bars(self):
return [v for v in self.__dict__.values() if isinstance(v, Bar)]
class Foo:
def __init__(self):
self._bar_names = {"bar1", "bar2"}
self.bar1 = Bar()
self.bar2 = Bar()
def bars(self):
return [self.__dict__[x] for x in self._bar_names]
__setattr__
class Foo:
def __init__(self):
self._bar_names = set()
self.bar1 = Bar()
self.bar2 = Bar()
def __setattr__(self, name, value):
if name == "_bar_names":
self.__dict__[name] = value
return
if isinstance(value, Bar):
self._bar_names.add(name)
else:
self._bar_names.discard(name)
self.__dict__[name] = value
def bars(self):
return [self.__dict__[x] for x in self._bar_names]
Upvotes: 1