• 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
Name
Last commit
Last update
golang Loading commit data...
gpython Loading commit data...
.gitignore Loading commit data...
CHANGELOG.rst Loading commit data...
COPYING Loading commit data...
MANIFEST.in Loading commit data...
README.rst Loading commit data...
setup.py Loading commit data...
tox.ini Loading commit data...