namespaces

Bengt Richter bokr at oz.net
Tue Aug 9 13:17:37 EDT 2005


On 31 Jul 2005 21:03:36 -0700, Paul Rubin <http://phr.cx@NOSPAM.invalid> wrote:

>Steven D'Aprano <steve at REMOVEMEcyber.com.au> 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



More information about the Python-list mailing list