Terry said:
Here a third, the closure approach (obviously not directly tested):
Just for grins, here's a fourth approach, using the descriptor protocol
... 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
... 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
<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".
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
... 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
... @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 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:
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: f() takes exactly 1 argument (2 given)
Regards,
Bengt Richter