Skip to main content
Code Review

Return to Answer

replaced http://stackoverflow.com/ with https://stackoverflow.com/
Source Link

I think I need my own space to explain "my approach" with default lambda - thanks to glglgl glglgl for hospitality :) .

I think I need my own space to explain "my approach" with default lambda - thanks to glglgl for hospitality :) .

I think I need my own space to explain "my approach" with default lambda - thanks to glglgl for hospitality :) .

added 122 characters in body
Source Link
volcano
  • 171
  • 3
>>> def test1(param, callback=lambda v:v):
 return callback(param)
>>> def test2(param, *callback):
 if callback:
 return callback[0](param)
 else:
 return param
 
>>> def test3(param, callback=None):
 if callback is not None:
 return callback[0]callback(param)
 else:
 return param
>>> dis.dis(test1)
 2 0 LOAD_FAST 1 (callback)
 3 LOAD_FAST 0 (param)
 6 CALL_FUNCTION 1
 9 RETURN_VALUE 
>>> dis.dis(test2)
 2 0 LOAD_FAST 1 (callback)
 3 POP_JUMP_IF_FALSE 20
 3 6 LOAD_FAST 1 (callback)
 9 LOAD_CONST 1 (0)
 12 BINARY_SUBSCR 
 13 LOAD_FAST 0 (param)
 16 CALL_FUNCTION 1
 19 RETURN_VALUE 
 5 >> 20 LOAD_FAST 0 (param)
 23 RETURN_VALUE 
 24 LOAD_CONST 0 (None)
 27 RETURN_VALUE 
>>> dis.dis(test3)
 2 0 LOAD_FAST 1 (callback)
 3 LOAD_CONST 0 (None)
 6 COMPARE_OP 9 (is not)
 9 POP_JUMP_IF_FALSE 2622
 3 12 LOAD_FAST 1 (callback)
 15 LOAD_CONST 1 (0)
 18 BINARY_SUBSCR 
 19 LOAD_FAST 0 (param)
 2218 CALL_FUNCTION 1
 2521 RETURN_VALUE 
 5 >> 2622 LOAD_FAST 0 (param)
 2925 RETURN_VALUE 
 3026 LOAD_CONST 0 (None)
 3329 RETURN_VALUE 

Surprise, surprise, *callbackNone loses by 2 bytecodes (did not see it coming), still - it is cleaner that *callback, which in semantically misleading, since it implies possibility of more than one value. And default callback overhead is less than 25% of any

>>> def test1(param, callback=lambda v:v):
 return callback(param)
>>> def test2(param, *callback):
 if callback:
 return callback[0](param)
 else:
 return param
 
>>> def test3(param, callback=None):
 if callback is not None:
 return callback[0](param)
 else:
 return param
>>> dis.dis(test1)
 2 0 LOAD_FAST 1 (callback)
 3 LOAD_FAST 0 (param)
 6 CALL_FUNCTION 1
 9 RETURN_VALUE 
>>> dis.dis(test2)
 2 0 LOAD_FAST 1 (callback)
 3 POP_JUMP_IF_FALSE 20
 3 6 LOAD_FAST 1 (callback)
 9 LOAD_CONST 1 (0)
 12 BINARY_SUBSCR 
 13 LOAD_FAST 0 (param)
 16 CALL_FUNCTION 1
 19 RETURN_VALUE 
 5 >> 20 LOAD_FAST 0 (param)
 23 RETURN_VALUE 
 24 LOAD_CONST 0 (None)
 27 RETURN_VALUE 
>>> dis.dis(test3)
 2 0 LOAD_FAST 1 (callback)
 3 LOAD_CONST 0 (None)
 6 COMPARE_OP 9 (is not)
 9 POP_JUMP_IF_FALSE 26
 3 12 LOAD_FAST 1 (callback)
 15 LOAD_CONST 1 (0)
 18 BINARY_SUBSCR 
 19 LOAD_FAST 0 (param)
 22 CALL_FUNCTION 1
 25 RETURN_VALUE 
 5 >> 26 LOAD_FAST 0 (param)
 29 RETURN_VALUE 
 30 LOAD_CONST 0 (None)
 33 RETURN_VALUE 

Surprise, surprise, *callback loses

>>> def test1(param, callback=lambda v:v):
 return callback(param)
>>> def test2(param, *callback):
 if callback:
 return callback[0](param)
 else:
 return param
 
>>> def test3(param, callback=None):
 if callback is not None:
 return callback(param)
 else:
 return param
>>> dis.dis(test1)
 2 0 LOAD_FAST 1 (callback)
 3 LOAD_FAST 0 (param)
 6 CALL_FUNCTION 1
 9 RETURN_VALUE 
>>> dis.dis(test2)
 2 0 LOAD_FAST 1 (callback)
 3 POP_JUMP_IF_FALSE 20
 3 6 LOAD_FAST 1 (callback)
 9 LOAD_CONST 1 (0)
 12 BINARY_SUBSCR 
 13 LOAD_FAST 0 (param)
 16 CALL_FUNCTION 1
 19 RETURN_VALUE 
 5 >> 20 LOAD_FAST 0 (param)
 23 RETURN_VALUE 
 24 LOAD_CONST 0 (None)
 27 RETURN_VALUE 
>>> dis.dis(test3)
 2 0 LOAD_FAST 1 (callback)
 3 LOAD_CONST 0 (None)
 6 COMPARE_OP 9 (is not)
 9 POP_JUMP_IF_FALSE 22
 3 12 LOAD_FAST 1 (callback)
 15 LOAD_FAST 0 (param)
 18 CALL_FUNCTION 1
 21 RETURN_VALUE 
 5 >> 22 LOAD_FAST 0 (param)
 25 RETURN_VALUE 
 26 LOAD_CONST 0 (None)
 29 RETURN_VALUE 

Surprise, surprise, None loses by 2 bytecodes (did not see it coming), still - it is cleaner that *callback, which in semantically misleading, since it implies possibility of more than one value. And default callback overhead is less than 25% of any

Post Migrated Here from stackoverflow.com (revisions)
Source Link
volcano
  • 171
  • 3

I think I need my own space to explain "my approach" with default lambda - thanks to glglgl for hospitality :) .

It saves you from having to check condition in the function. And the overhead? Not that much (here comes dis, which I - alas! - nearly never use)

dis.dis(lambda v: v)
 1 0 LOAD_FAST 0 (v)
 3 RETURN_VALUE 

But how bad is it - compared to other approaches? See below

>>> def test1(param, callback=lambda v:v):
 return callback(param)
>>> def test2(param, *callback):
 if callback:
 return callback[0](param)
 else:
 return param
 
>>> def test3(param, callback=None):
 if callback is not None:
 return callback[0](param)
 else:
 return param
>>> dis.dis(test1)
 2 0 LOAD_FAST 1 (callback)
 3 LOAD_FAST 0 (param)
 6 CALL_FUNCTION 1
 9 RETURN_VALUE 
>>> dis.dis(test2)
 2 0 LOAD_FAST 1 (callback)
 3 POP_JUMP_IF_FALSE 20
 3 6 LOAD_FAST 1 (callback)
 9 LOAD_CONST 1 (0)
 12 BINARY_SUBSCR 
 13 LOAD_FAST 0 (param)
 16 CALL_FUNCTION 1
 19 RETURN_VALUE 
 5 >> 20 LOAD_FAST 0 (param)
 23 RETURN_VALUE 
 24 LOAD_CONST 0 (None)
 27 RETURN_VALUE 
>>> dis.dis(test3)
 2 0 LOAD_FAST 1 (callback)
 3 LOAD_CONST 0 (None)
 6 COMPARE_OP 9 (is not)
 9 POP_JUMP_IF_FALSE 26
 3 12 LOAD_FAST 1 (callback)
 15 LOAD_CONST 1 (0)
 18 BINARY_SUBSCR 
 19 LOAD_FAST 0 (param)
 22 CALL_FUNCTION 1
 25 RETURN_VALUE 
 5 >> 26 LOAD_FAST 0 (param)
 29 RETURN_VALUE 
 30 LOAD_CONST 0 (None)
 33 RETURN_VALUE 

Surprise, surprise, *callback loses

As for run-time impact - try timing runs with different implementations, and see for yourself

lang-py

AltStyle によって変換されたページ (->オリジナル) /