• Kirill Smelkov's avatar
    golang: Fix `@func(cls) def name` not to override `name` in calling context · 924a808c
    Kirill Smelkov authored
    With @func being a decorator, the following
    
    	@func(cls)
    	def name():
    		...
    
    is always processed by python as
    
    	name = func(cls)(def name(): ...)
    
    Before this patch it was leading to name being overridden with None:
    
    	def f():
    		print 'hello'
    
    	class C:
    		pass
    
    	@func(C)
    	def f(c):
    		print 'C.f', c
    
    	f()
    	Traceback (most recent call last):
    	  File "<console>", line 1, in <module>
    	TypeError: 'NoneType' object is not callable
    
    We can fix it by returning from `func(cls)(def name(): ...)` the
    original `name` object from the calling context.
    
    Unfortunately if `name` was not previously set I did not find a way(*) to
    avoid polluting the calling namespace where it is set to what @func(cls)
    returns (None) by the hardcoded way how python processes decorators:
    
    	In [2]: c = """
    	   ...: @fff
    	   ...: def ccc():
    	   ...:     return 1
    	   ...: """
    
    	In [3]: cc = compile(c, "file", "exec")
    
    	In [4]: dis(cc)
    	  2           0 LOAD_NAME                0 (fff)
    	              3 LOAD_CONST               0 (<code object ccc at 0x7fafe58d0130, file "file", line 2>)
    	              6 MAKE_FUNCTION            0
    	              9 CALL_FUNCTION            1
    	             12 STORE_NAME               1 (ccc)	<-- NOTE means: ccc = what fff() call returns
    	             15 LOAD_CONST               1 (None)
    	             18 RETURN_VALUE
    
    At least with no overriding taking place the situation is better now.
    
    NOTE: it is only @func(cls) which potentially pollutes calling
    namespace. Just @func (without class) is always clean because by
    definition it works as a regular decorator.
    
    (*) there is a very low-level and potentially fragile way to disable
    STORE_NAME after CALL_FUNCTION by dynamically patching caller's bytecode
    at runtime and replacing STORE_NAME with POP_TOP + NOP...
    924a808c
__init__.py 21 KB