22
class Foo(object):
    def tick(self):
        print("something")

class Bar(object):
    def __init__(self):
        self.foo = Foo()

    def tick(self):
        #Here's what I do....
        self.foo.tick()

        #here's what my goal would be
        self.foo()

b = Bar()
b.tick()

That's essentially my goal. From what I've gathered I could change the tick function to __call__ and that would allow me to do what I wanted. A couple of the other answers said that this would make a new instance of the object, does that mean that it would use self.foo's memory? or would it make a whole new object, newly instanced? or make a copy of self.foo?

Also a couple of drawbacks to this which may or may not manifest themselves come to mind. For a particular part of my program, I check to see if the object has a __call__ to determine if the argument I'm passing is a function or a variable, and I don't really think I would want to allow that to be called (even though, I suppose the class technically would be a function at that point.) Is there any way to distinguish between a function and a callable class?

Is there anything else that would make doing this undesirable (and is it a pythonic way to work?)? My next thought had been that given that other variable prefixed with __ cant be used outside their class, but that doesnt seem to be the case here.

Bakuriu
  • 98,325
  • 22
  • 197
  • 231
DanielCardin
  • 545
  • 2
  • 8
  • 17
  • 1
    Implementing `__call__` would *not* create new instances of the object. Doing `TheClass()` creates a new instance but `some_instance()` simply calls `__call__`. – Bakuriu Jan 29 '13 at 15:11
  • I'm only mentioning this in case you haven't thought of it -- But, with the extremely simple code you have above, making `Bar` inherit from `Foo` seems like a good bet -- Of course your use-case might make it not a good bet ... – mgilson Jan 29 '13 at 15:28

2 Answers2

30

Changing tick(self) to __call__(self) is the correct solution.

This has nothing to do with memory allocation. All __call__ signifies is the function which Python calls when you use (for an object foo) the syntax foo().

For your later question: to check whether something is an object, use isinstance or issubclass (possibly with the object class). And in my mind this answer is better than the accepted one for the "How do I determine if something is a function?" question you've probably seen.

Community
  • 1
  • 1
Borealid
  • 95,191
  • 9
  • 106
  • 122
22

To make a class instance callable, all you need to do is implement a __call__ method. Then, to call the __call__ method, you just do: instance(arg1,arg2,...) -- in other words, you call the instance the same way you would call a function.

Note that you can alias __call__ with some other method defined on the class if you want:

>>> class Foo(object):
...     def tick(self):
...         print ("something")
...     __call__ = tick
... 
>>> a = Foo()
>>> a()
something
>>> a.tick()
something
mgilson
  • 300,191
  • 65
  • 633
  • 696
  • if you were to implement a function that takes arguments, can you still use this aliasing method? or does it only work when the function has only one argument `self` – Ajay Feb 24 '15 at 22:01
  • I'm trying to make it so that different instances have different __call__ methods. However, if I set self.__call__ within __init__(), when I actually call instance(), I get TypeError: 'CallableClass' object is not callable. Is there a way to set __call__ differently instance-to-instance? – Nick Crews Nov 03 '17 at 17:46
  • 1
    You can have a `_delegate` property which `__call__` will delegate to: `def __call__(self): self._delegate()` – mgilson Nov 04 '17 at 01:41