On Tue, 26 Apr 2005 10:26:51 -0700, Michael Spencer <[EMAIL PROTECTED]> wrote:
>Terry Reedy wrote: >> "Charles Krug" <[EMAIL PROTECTED]> wrote in message >> news:[EMAIL PROTECTED] >> >>>Both of these techniques look promising here. >> >> >> Here a third, the closure approach (obviously not directly tested): >> >> >> >Just for grins, here's a fourth approach, using the descriptor protocol > > >>> def func_with_state(state,a): > ... state.append(a) > ... return state > ... > >>> f = func_with_state.__get__([]) > >>> f(1) > [1] > >>> f(2) > [1, 2] > >>> f(3) > [1, 2, 3] > >>> > For those who don't recognize it, this is the mechanism that binds instances to methods of their type to make bound methods. It's as if you had given list a new method and picked up the bound method from an instance like [].func_with_state >>> def func_with_state(state, a): ... state.append(a) ... return state ... >>> f = func_with_state.__get__([]) >>> f <bound method ?.func_with_state of []> The '?' is because we didn't supply the second argument to __get__, i.e., type([]) >>> f = func_with_state.__get__([], list) >>> f <bound method list.func_with_state of []> >>> f.im_func <function func_with_state at 0x02EFD614> >>> func_with_state <function func_with_state at 0x02EFD614> For grins, here's a fifth approach (I'm assuming you counted correctly to the fourth ;-) >>> from ut.presets import presets >>> @presets(state=[]) ... def f(a): ... state.append(a) ... return state ... >>> f(1) [1] >>> f(2) [1, 2] >>> f(3) [1, 2, 3] This is a straight function, with byte-code hack preset of internal state as specified. The disassemby shows [1, 2, 3] because that is the object referred to still. What would have been a global reference got hacked to LOAD_FAST 1 (state) after preset from "constant". >>> import dis >>> dis.dis(f) 1 0 LOAD_CONST 1 ([1, 2, 3]) 3 STORE_FAST 1 (state) 3 6 LOAD_FAST 1 (state) 9 LOAD_ATTR 1 (append) 12 LOAD_FAST 0 (a) 15 CALL_FUNCTION 1 18 POP_TOP 4 19 LOAD_FAST 1 (state) 22 RETURN_VALUE To see the initial state, we have to re-decorate another instance of f: >>> >>> @presets(state=[]) ... def f(a): ... state.append(a) ... return state ... >>> dis.dis(f) 1 0 LOAD_CONST 1 ([]) 3 STORE_FAST 1 (state) 3 6 LOAD_FAST 1 (state) 9 LOAD_ATTR 1 (append) 12 LOAD_FAST 0 (a) 15 CALL_FUNCTION 1 18 POP_TOP Of course, we could put this inside a factory and pass the desired state >>> def factory(state): ... @presets(state=state) ... def f(a): ... state.append(a) ... return state ... return f ... >>> f2 = factory([111,222]) >>> f2('third') [111, 222, 'third'] >>> dis.dis(f2) 2 0 LOAD_CONST 1 ([111, 222, 'third']) 3 STORE_FAST 1 (state) 4 6 LOAD_FAST 1 (state) 9 LOAD_ATTR 1 (append) 12 LOAD_FAST 0 (a) 15 CALL_FUNCTION 1 18 POP_TOP 5 19 LOAD_FAST 1 (state) 22 RETURN_VALUE >>> dis.dis(factory('append will fail')) 2 0 LOAD_CONST 1 ('append will fail') 3 STORE_FAST 1 (state) 4 6 LOAD_FAST 1 (state) 9 LOAD_ATTR 1 (append) 12 LOAD_FAST 0 (a) 15 CALL_FUNCTION 1 18 POP_TOP 5 19 LOAD_FAST 1 (state) 22 RETURN_VALUE Note that the function takes only one argument: >>> f2 <function f at 0x02EF841C> >>> f2.func_code.co_argcount 1 >>> f2(10, 'fails') Traceback (most recent call last): File "<stdin>", line 1, in ? TypeError: f() takes exactly 1 argument (2 given) Regards, Bengt Richter -- http://mail.python.org/mailman/listinfo/python-list