1

I have 2 modules, each contains a class.
My main program instantiates an object of class One, which instantiates many objects of class Two.
I need to be able to call a function in class One from the instances of class Two.
This is a general look of what I have:

module mod_one.py:

import mod_two

class One:
    def __init__(self):
        self.new_instance = Two()

    def call_back_func(self):
        # This function should be called 
        # from the new instance of class Two()

module mod_two.py:

class Two:
    def __init__(self):
        # Call call_back_func() of module mod_one

The only way I found was to pass the callback function call_back_func() as an argument to class Two like so:

self.new_instance = Two(self.call_back_func)

but I'd like to know if there is a better way of doing that.

user1102018
  • 4,369
  • 6
  • 26
  • 33

3 Answers3

2

I think there's a trade-off here between simplicity and loose coupling. In my opinion, the simplicity would be passing the callback to an object, while loose coupling would be using a framework to pass signals between the objects.

For instance, if you use blinker signaling library you could use this alternative design:

from blinker import signal

class One:
    def __init__(self):
        self.two = Two()
        self.two.some_signal.connect(self.callback)

    def callback(self, data):
        print 'Called'

class Two:
    some_signal = signal('some_signal')

    def process(self):
        # Do something                                
        self.some_signal.send()

one = One()
one.two.process()

In code above, the Two object doesn't even know if there's some other object interested in its internal state changes. However, it does notify about them by emitting a signal that might be used by other objects (in this case a One object) to perform some specific action.

A good example about this approach is a GUI framework. When a button widget is created, it's not needed to pass a callback that should be executed when the button is clicked. However, the button emits the clicked signal and whatever callback is subscribed to that signal is executed to perform the desired action.

jcollado
  • 39,419
  • 8
  • 102
  • 133
  • Thanks, I'll give it a try, although the comments above encourage me to "not fix it if it ain't broken" :) – user1102018 Dec 21 '11 at 20:05
  • I agree with those comments, I believe you just need to know about other alternatives just in case in the future you find you're passing too many callbacks around. – jcollado Dec 21 '11 at 20:21
  • I came here for an example with blinker on how to call an object's method if a signal is emitted. I found your example very useful, thanks. – Jabba Jun 28 '13 at 15:28
1

What you are doing is perfectly valid. Notice that __init__ is not a constructor. It is just an initialization method. (__new__ is the Python's constructor method)

More on this topic can be found in question Python's use of __new__ and __init__?

Community
  • 1
  • 1
gecco
  • 17,969
  • 11
  • 51
  • 68
  • -1: I fail to see any significant way in which `__init__` is unlike the concept of constructors from other languages. `__new__` OTOH is a concept that doesn't exist in languages like Java/C++, so I don't understand how you can say it's a better fit for the concept. I think "`__init__` is not a constructor" is a myth, and an unhelpful one at that. The official python docs even refer to `__init__` as a constructor! http://docs.python.org/reference/datamodel.html#basic-customization – Ben Dec 21 '11 at 20:44
  • Before entering the constructor, which assigns values to the members. Exactly as in Java and C++. The only difference is that they provide no facility like `__new__` to customise the process of coming up with the new instance. – Ben Dec 21 '11 at 21:11
  • If I'm not wrong, such circular dependencies are not possible in other programming languages. In Python they are... So you must agree that Python handles differently object creation?! – gecco Dec 22 '11 at 07:15
  • What circular dependencies? Objects A and B that each contain a reference to the other? That's fairly trivial in any OO language, and you have to set up the links after both objects exist, just as in Python. In all of Python, Java, and C++ when you call `MyClass(args)` the system will allocate a new instance, then invoke the constructor on that instance. The purpose of the constructor is to initialise the members of a blank instance such that normal invariants for the class are set up. – Ben Dec 22 '11 at 07:58
  • Doesn't seem to be handled that differently to me, except that Python allows you to customise the "system allocates a new instance" bit. Why would you call `__new__` a constructor? (And again, the official Python docs don't call `__new__` a constructor, but do refer to `__init__` as one. – Ben Dec 22 '11 at 08:02
0

I think you are missing an object here. Specifically the Creational Builder Pattern

class OneTwoBuilder:

  def createOne(self, num_of_two=0):
      o = One()
      child = []
      for _ in xrange(num_of_two):
          t = Two()
          o.callback(t)
          child.append(t)
      o.setChilds(child)
      return o
fabrizioM
  • 46,639
  • 15
  • 102
  • 119