0

I did a complex class and now I have to track it and register it in a bigger class for management.

The problem, is that the complex class may create a new instance of itself. Therefore, I have to detect this new creation in my manager.

The other problem is that there is not only one manager. They're used like a session manager. Each has a initial complex object in it. If the complex object instantiates a new instance of itself, only the good manager must be warned.

Here is an example of code to present my problem:

class Foo:
    def create_another(self):
        # Do something
        return Foo()

class Manager:
    def __init__(self):
        init_object = SomeDecorator(Foo()) # I guess there will be a decorator
        self.objects = [init_objects]

m1 = Manager()
assert len(m1.objects) == 1

m1.objects[0].create_another()
assert len(m1.objects) == 2

m2 = Manager()
assert len(m1.objects) == 2
assert len(m2.objects) == 1

m1.objects[0].create_another()
assert len(m1.objects) == 3
assert len(m2.objects) == 1

m2.objects[0].create_another()
assert len(m1.objects) == 3
assert len(m2.objects) == 2
tshepang
  • 12,111
  • 21
  • 91
  • 136
  • TBH I'm not really sure what you're asking here... It would help if you asked something a bit more specific? – James Mills May 22 '14 at 13:16
  • The class *Foo* is a tree node and may create new node as new child. I want to save the creation of new node by context (Manager).There is no logical link between Manager and Foo so i don't think it's good to edit Foo class. The *Manager* class is here to load/save trees and add a service layer in my architecture. – Pierre Turpin May 22 '14 at 14:12
  • The second assert should be for m1 right ? – Jean-Marie Comets May 22 '14 at 14:19
  • It's hard to tell because what you want is vague, but this sounds like a good use-case for circuits Component architecture and events. See: https://circuits.readthedocs.org/ – James Mills May 22 '14 at 14:24

3 Answers3

1

Just sketching out an idea (incomplete / untested):

  1. provide the manager as parameter: Foo.__init__(self, manager) and store it as attribute
  2. You'll have to call init_object = Foo(self) in Manager.__init__()
  3. then, you can use the info about the manager in your create_another() method to
    • instantiate the new instance correctly
    • modify the Manager.objects-list (I would recommend a method instead of modifying it direclty)
OBu
  • 4,977
  • 3
  • 29
  • 45
  • The is no logical link between *Foo* and *Manager*. I don't really want to change the *Foo* class. Using a decorator is not a problem – Pierre Turpin May 22 '14 at 14:19
0

If your Foo objects can only be tracked by one manager at a time, this can simply be accomplished by notifying it when calling create_another.

Example code:

class Foo:
    def __init__(self, manager=None):
        self.manager = manager

    def create_another(self):
        # do something
        foo = Foo(self.manager)
        if self.manager is not None:
            self.manager.notify_object_created(foo)
        return foo

class Manager:
    def __init__(self):
        init_object = SomeDecorator(Foo(self))
        self.objects = [init_object]

    def notify_object_created(self, foo):
        self.objects.append(foo)

Edited after reading the comments:

If you don't want to change the Foo class, the other solution is to dynamically decorate Foo's constructor, by tracking it, adding the above feature to it.

Example code:

class Foo:
    def create_another(self):
        # do something
        return Foo()

class Manager:
    def __init__(self):
        self.objects = []
        self.track(Foo())

    def track(self, foo):
        def decorated_create_another():
            new_foo = foo._create_another()
            self.track(new_foo)
            return new_foo
        foo._create_another = foo.create_another
        foo.create_another = decorated_create_another
        self.objects.append(foo)

Of course, this doesn't check for overriding an existing _create_another method, tracking the same Foo object several times, etc...

Jean-Marie Comets
  • 706
  • 2
  • 7
  • 21
  • In fact my example code is not the real case in my project ><. The *create_another* doesn't return anything (in real it's a bool to know the success of the operation). I guess the decorator redefine `__init__` or `__new__` of the Foo object. But i don't know how – Pierre Turpin May 22 '14 at 14:53
-2

That's what __new__ is for, isn't it?

https://stackoverflow.com/a/13054570/705086

Community
  • 1
  • 1
Dima Tisnek
  • 11,241
  • 4
  • 68
  • 120