[Twisted-Python] RPC design questions

Tobias Oberstein tobias.oberstein at tavendo.de
Sat Aug 27 09:15:04 MDT 2011


I thought I can strictly stick to the advice (only keep one variant -- I thought I keep "lambda"),
but today Python surprised me (which happens not so often).

Check out these snippets:

(1)
   def get(self, keys):
      for key in keys:
         self.call("keyvalue:get", key).addCallback(lambda value: self.show(key, value))

(2)
   def get(self, keys):
      for key in keys:
         self.call("keyvalue:get", key).addCallback(partial(self.show, key))

(3)
   def get(self, keys):
      for key in keys:
         self.call("keyvalue:get", key).addCallback(lambda value, key = key: self.show(key, value))

==

(2) and (3) will output the same. Not (1).

The reason is, that lambda establishes a closure over the reference "key", which changes
with loop iteration, and when the RPCs come back, that "key" will have the last value of the
list iterated over.

The result of (1) was not what I expected, and it took me some googling to find the answers.

(3) is somewhat a hack on lambda to establish closures over the value when the closure is
constructed, not the reference.

(2) does that by default.

I have some background in Erlang, where everything is immutable, and thus the issue is non.
This is where the half-functional character of Python has bitten me badly.

It may be nothing new to many, but it certainly was for me.

http://blog.markfeeney.com/2009/11/python-lambda-partial-and-scopes.html
http://stackoverflow.com/questions/938429/scope-of-python-lambda-functions-and-their-parameters
http://math.andrej.com/2009/04/09/pythons-lambda-is-broken/

==

Anyway, perhaps it's still easier for users to grasp (3) than having another construct (2).

What do you think?


Von: twisted-python-bounces at twistedmatrix.com [mailto:twisted-python-bounces at twistedmatrix.com] Im Auftrag von Glyph Lefkowitz
Gesendet: Dienstag, 23. August 2011 20:30
An: Twisted general discussion
Betreff: Re: [Twisted-Python] RPC design questions


On Aug 23, 2011, at 10:37 AM, Tobias Oberstein wrote:


class AutobahnDeferred(Deferred):
  def call(self, *args):
     return self.addCallback(self.protocol.rcall, *args)

Pro:    most terse
Con:    only supports single callback no errback


Con: subclassing in general is a bad idea.  Subclassing Deferred is an even worse idea.  What if Deferred one day gets a new method called 'call' that does something different?  Your code would all break.

Anything why I shouldn't do?

Providing three different ways to do the same thing just so that you can use different syntax depending on your mood is a recipe for making your code hard to read.  Pick one style, stick to it as much as possible - consistency is more important than the benefits of any one particular style :).

(Except the subclassing one.  Don't do that.)

-glyph

-------------- next part --------------
An HTML attachment was scrubbed...
URL: </pipermail/twisted-python/attachments/20110827/7fabacd5/attachment-0001.html>


More information about the Twisted-Python mailing list