On 31 Jul 2005 21:03:36 -0700, Paul Rubin <http://[EMAIL PROTECTED]> wrote:
>Steven D'Aprano <[EMAIL PROTECTED]> writes: >> Most languages can create self-modifying code. That's not the >> question. The question is whether developers should write >> self-modifying code, not whether language designers should prohibit it. > >There was no self-modifying code in that closure example. >Self-modifying code means something entirely different. > >Closures are a tried and true technique that are thematic in Lisp >programming (Python tends to use class instances instead). They take >some getting used to, just like, say, recursion. And like almost >anything, they can be abused. But they're a completely legitimate >approach to lots of types of problems. > >See the book "Structure and Interpretation of Computer Programming" >for an intro to programming based on closures. If you are referring to the code that defines translate with a def and also internally defines the same global translate with an internal def that binds globally (because of the global declaration) when it executes, then I agree, translate is not "self"-modifying, but it is self's-global-binding-modifying, which seems like a close cousin to self-modification ;-) Note that the global binding changes after the first execution: >>> def translate( text ): ... import string ... all=string.maketrans('','') ... badcars=all.translate(all,string.letters+string.digits) ... TABLE = string.maketrans(badcars,'_'*len(badcars)) ... global translate ... def translate( text ): ... return text.translate(TABLE) ... return translate( text ) ... >>> dir() ['__builtins__', '__doc__', '__name__', 'translate'] Here is what translate is bound to after the above def: >>> import dis >>> dis.dis(translate) 2 0 LOAD_CONST 0 (None) 3 IMPORT_NAME 0 (string) 6 STORE_FAST 2 (string) 3 9 LOAD_FAST 2 (string) 12 LOAD_ATTR 1 (maketrans) 15 LOAD_CONST 1 ('') 18 LOAD_CONST 1 ('') 21 CALL_FUNCTION 2 24 STORE_FAST 1 (all) 4 27 LOAD_FAST 1 (all) 30 LOAD_ATTR 3 (translate) 33 LOAD_FAST 1 (all) 36 LOAD_FAST 2 (string) 39 LOAD_ATTR 4 (letters) 42 LOAD_FAST 2 (string) 45 LOAD_ATTR 5 (digits) 48 BINARY_ADD 49 CALL_FUNCTION 2 52 STORE_FAST 3 (badcars) 5 55 LOAD_FAST 2 (string) 58 LOAD_ATTR 1 (maketrans) 61 LOAD_FAST 3 (badcars) 64 LOAD_CONST 2 ('_') 67 LOAD_GLOBAL 7 (len) 70 LOAD_FAST 3 (badcars) 73 CALL_FUNCTION 1 76 BINARY_MULTIPLY 77 CALL_FUNCTION 2 80 STORE_DEREF 0 (TABLE) 7 83 LOAD_CLOSURE 0 (TABLE) 86 LOAD_CONST 3 (<code object translate at 02EE5E60, file "<stdin>",line 7>) 89 MAKE_CLOSURE 0 92 STORE_GLOBAL 3 (translate) 9 95 LOAD_GLOBAL 3 (translate) 98 LOAD_FAST 0 (text) 101 CALL_FUNCTION 1 104 RETURN_VALUE Execute once: >>> translate('something') 'something' Now check what translate is bound to: >>> dis.dis(translate) 8 0 LOAD_FAST 0 (text) 3 LOAD_ATTR 1 (translate) 6 LOAD_DEREF 0 (TABLE) 9 CALL_FUNCTION 1 12 RETURN_VALUE I.e., the original globally bound translate replaces its global binding with the closure it creates on first execution, and also uses that closure to get the first result, which is a little tricky, I'd say ;-) Regards, Bengt Richter -- http://mail.python.org/mailman/listinfo/python-list