0

In Javascript, bind, call, and apply allow you to change the reference to this on demand. I'm looking at a situation in Python where the code would look a bit nicer if I were able to do this instead of using getattr.

I'd like to pass a reference to a method, but change the instance the method refers to within a thread. In Javascript, I'd like to do this:

function produce (x) {
   enqueue(this.api.delete.bind(this.api, x))
}

function consume () { 
   api = new API()
   task = dequeue()
   task.call(api)
}

In Python, I have to do this:

def produce(self, x):
   enqueue(partial(self.api.delete, x))

def consume(self):
   api = API()
   task = dequeue() # callable
   ?????????

This may look a little odd, but what's going on is each api instance is running on a separate thread. getattr works, but I would prefer to pass verbs instead of nouns to the queue.

SapphireSun
  • 9,170
  • 11
  • 46
  • 59

2 Answers2

2

You can enqueue a lambda closing over x and waiting for its api instance:

enqueue(lambda api: api.delete(x))

And later just pass the API object:

task = dequeue()
task(api)

You also can get an "unbound method reference" in Python 3, to which you can later pass self, by simply naming the class member:

>>> class A:
...    def foo(self, x):
...       print(x)
... 
>>> f = A.foo
>>> f(A(), 1)  # equivalent to A().foo(1)
1
>>> f
<function A.foo at 0x7f86c9b872f0>

(IIRC, it will behave the same in Python 2, but the type of f will be something special.)

phipsgabler
  • 20,535
  • 4
  • 40
  • 60
2

Related to (OK, basically identical to) phg's answer, the operator module provides a methodcaller function, which takes a method name (and optionally, arguments for that method) and returns a new callable which, when called with an object, invokes the named method on the object with the given arguments.

from operator import methodcaller

# methodcaller('foo', arg1)(thing) == thing.foo(arg1)

def produce(self, x):
   enqueue(methodcaller('delete', x))

def consume(self):
   api = API()
   task = dequeue() # callable
   task(api)
chepner
  • 497,756
  • 71
  • 530
  • 681