1

Okay, so what I am trying to do is to create a function that will find an object instance based on the value of a specific attribute that all objects of the class share. Essentially, I want Python to search through the specific attribute of each instance of the class, and check it against another value, and if it finds a match to do some stuff. In pseudocode:

for each instance of Class:
    if search_keyword is in instance.attribute:
        do some stuff
        found = True

if found is True:
    tell_user("Found instance!")

If more detail is required on the nature of my inquiry, then:

What I am doing is essentially using the object as an extended dictionary. I have multiple attributes attached to the object, and I want to search through them. I am essentially using it as a storage container, which I need to search through.

If there is a better way to store said information other than objects, please share.

I'm essentially using it as a dictionary with multiple keys.

Aristides
  • 3,805
  • 7
  • 34
  • 41
  • 2
    As a knee-jerk reaction, anything which acts on *every instance* ever of a class seems like awful design. Why can't you explicitly maintain a collection of the objects? –  Jun 22 '13 at 16:46
  • My only goal is to be able to do what it says above. If you need to replace every instance with a collection that has every instance, so be it. – Aristides Jun 22 '13 at 17:19
  • For me the existance of the need to do this seems to point to a deeper design problem. ;) – Tobias Hermann Jun 22 '13 at 17:46
  • As a complement, Python is more about "duck typing" than "strict inheritance typing". It is clearly feasible to find all the instances of one of your classes -- but awfully difficult to obtain all "objects that behave like" instance of your class -- and so _could_ be used like instances of your class. Not mentioning that this kind of automagical global knowledge will lead to subtle bugs if you ever use threads in your app... and will easily become a nightmare for anyone that will maintain your code. – Sylvain Leroux Jun 22 '13 at 17:53
  • This is a common question. The short answer is: roll your own mechanism. – Marcin Jun 22 '13 at 18:05

1 Answers1

2

You could do this easily enough by having a class attribute which is a list of all instances of that class ever created, and having the __init__ of each instance of the class add the instance to the list.

class Foo(object):
    list_of_all_foos = []

    def __init__(self):
        Foo.list_of_all_foos.append(self)

Then to search all the Foo instances you've created:

for foo_instance in Foo.list_of_all_foos:
    if search_keyword is in foo_instance.attribute:
        do some stuff
        found = True

if found is True:
    tell_user("Found instance!")

Alternatively, to do this with a class method, which might be a little more idiomatic:

class Foo(object):
    list_of_all_foos = []

    @classmethod
    def create_foo_and_add_to_list(cls, *args, **kwargs):
        new_foo = cls(*args, **kwargs)
        Foo.list_of_all_foos.append(new_foo)
        return new_foo
Mark Amery
  • 143,130
  • 81
  • 406
  • 459
  • Okay, I got it to work this way. Thanks! As I said, I am using the objects as data containers. Why does it seem like it is bad to do this? – Aristides Jun 22 '13 at 18:36
  • @Aristides It's just not very common to use class variables to store data for use from outside the class, or to have object initialization have side effects that influence things beyond the class. It would be more usual to have your `list_of_all_foos` be a variable in whatever scope can be seen by the creators and searchers of your `Foo` objects (e.g. have it as a module variable somewhere), and have the code that creates new `Foo` instances take responsibility for adding them to the list, rather than that being `Foo.__init__`'s job. – Mark Amery Jun 22 '13 at 18:48
  • ohhh I see. I might try that. But is there anything wrong with how it is now? (unintended side effects)? – Aristides Jun 22 '13 at 18:51
  • Basically, I can see two downsides to doing things your way: 1) It's unusual and unidiomatic, which is potentially a bad thing if others are going to use your code or if you want to condition yourself into using 'best practices', and 2) It'll be harder for you to modify your code in future to have some second, totally separate and unrelated collection of `Foo` objects, because every time you create a `Foo` to add to the second collection, it'll automatically get added to the first one. You're needlessly baking information about *how the data objects will be used* into their class itself. – Mark Amery Jun 22 '13 at 18:54
  • @Aristides However, there might be an *advantage* to your way if you have these objects being instantiated from all over the place in your codebase but need them all to be added to the same, single collection. (Dunno why this would be the case, but anyway...) In that case, the slightly more idiomatic way to handle this - rather than having your `__init__` method add the `Foo` objects to the collection - would be to have a class method on your class that creates a new `Foo`, adds it to the collection, and returns it. From outside, you'd call `Foo.create_foo_and_add_to_list()` instead of `Foo()` – Mark Amery Jun 22 '13 at 19:01
  • so the other method would be the same as __init__ pretty much, except with the adding to list part? – Aristides Jun 22 '13 at 19:09
  • Also, the list of objects returns ". This doesn't interfere with the rest of the program, but is that supposed to happen? – Aristides Jun 22 '13 at 19:14
  • @Aristides I've edited my answer with an example of how to write an initializer method that calls `__init__` and also does the other shit you need. And yeah, that's what you expect to see when you view the list at the interpreter or call `str()` on it. To change that, you'd need to override the `__repr__` magic method of the class. – Mark Amery Jun 22 '13 at 19:21