Results 1 to 5 of 5

Thread: Python: Lambda or Partial?

  1. #1
    undefined fsanges's Avatar
    Join Date
    Jul 2013
    Location
    Montreal
    Posts
    6

    Default Python: Lambda or Partial?



    Lambda or Partial? Is there a preferred solution to pass an argument to a callback?

    Using partial:

    Code:
    #partial
    
    from functools import partial
    import maya.cmds as mc
    
    
    class ButtonWin(object):
        def __init__(self):
            self.win = mc.window()
            self.layout = mc.columnLayout(parent=self.win)
            for numberX in range(10):
                mc.button(label="Click Here %d" % numberX, parent=self.layout, command=partial(self.report, numberX)) #PARTIAL
                mc.showWindow()
    
        def report(self, buttonIndex, value):
            print "button %d got %s" % (buttonIndex, value)
    
    f = ButtonWin()
    Or Lambda:

    Code:
    #Lambda
    
    import maya.cmds as mc
    
    
    class ButtonWin(object):
        def __init__(self):
            self.win = mc.window()
            self.layout = mc.columnLayout(parent=self.win)
            for numberX in range(10):
                mc.button(label="Click Here %d" % numberX, parent=self.layout, command=lambda x: self.report(numberX, "True")) #LAMBDA
                mc.showWindow()
    
        @staticmethod
        def report(buttonIndex, value):
            print "button %d got %s" % (buttonIndex, value)
    
    f = ButtonWin()


    Thanks in advance!

  2. #2
    struct
    Join Date
    Mar 2011
    Location
    San Francisco
    Posts
    348

    Default

    I always use partial, though I know some people find lambdas easier to read and use them. For the most part they will behave exactly the same and whichever you choose will be personal preference.

    For the most part...
    If you are creating callbacks in a loop, and using a loop variable as an argument for the callback, then you should use partial. lambda evaluates the variable at runtime, whereas partial evaluates when the partial function is created. An example:

    Code:
    def printValue(v):
        print v
        
    def lambdas():    
        callbacks = []
        for i in range(5):
            callbacks.append(lambda: printValue(i))
            
        for cb in callbacks:
            cb()
            
    def partials():
        from functools import partial
        callbacks = []
        for i in range(5):
            callbacks.append(partial(printValue, i))
            
        for cb in callbacks:
            cb()
            
    print 'lambdas:'
    lambdas()
    print 'partials:'
    partials()
    
    # 
    lambdas:
    4
    4
    4
    4
    4
    partials:
    0
    1
    2
    3
    4
    This isn't just an issue in for loops. If you change the value of a variable that is referenced in a lambda function you will get an unexpected result since it will resolve that variable whenever the lambda is called, not when it was created.
    Last edited by capper; 10-04-2014 at 12:03 AM.

  3. #3
    struct
    Join Date
    Mar 2011
    Location
    San Francisco
    Posts
    348

    Default

    I should add that you actually can get lambdas to resolve variables at creation by passing them as default arguments. I just find it more unsightly (and don't know if there are any gotchas or side-effects with this method).

    Code:
    callbacks = []
    for i in range(5):
        callbacks.append(lambda x=i: printValue(x))
    
    for cb in callbacks:
       cb()
    
    0
    1
    2
    3
    4

  4. #4
    program Theodox's Avatar
    Join Date
    Mar 2012
    Location
    Seattle
    Posts
    1,107

    Default

    In a simple context (just making a single callback or a series of one-off calls) lambdas are fine. If you're re-using variables - which includes any form of looping (!!) partials are better because they don't suffer from late resolution the way lamdas do.

    Details here:
    http://techartsurvival.blogspot.com/...eat-sheet.html

  5. #5
    undefined fsanges's Avatar
    Join Date
    Jul 2013
    Location
    Montreal
    Posts
    6

    Default

    Thanks a lot for the info capper and Theodox! That's really helpful.

    Cheers!

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •