Do pythons like sugar?

Michele Simionato mis6 at pitt.edu
Thu Jan 9 17:37:56 CET 2003


Afanasiy <abelikov72 at hotmail.com> wrote in message news:<6u6q1vk7dgjps43t0uuk8eut1ghlgnoc71 at 4ax.com>...
> I've written this method for a text formatting class...
> But it's ugly as sin. With all those self's I consider
> it much less readable than it could be...
> 
> A few languages provide syntax sugar for dealing with
> this by allowing you to localize the class scope.
> 
> Does Python? eg. `with self do:`
> 
>   def format( self, width=80 ):    
>     self.lines = ['']
>     i = 0
>     for word in self.text.split():  
>       if self.textwidth(self.lines[i]) + self.textwidth(word) <= width:
>         if self.textwidth(self.lines[i]) > 0:
>           self.lines[i] += ' '
>         self.lines[i] += word
>       else:
>         i += 1
>         self.lines.append(word)
You may get rid of self with dirty tricks. 

I have posted few days ago a solution involving metaclasses which allows
Python to recognize _x as a shortcut for self.x. For instance your code
would read

from noself import Noself

class D(Noself):
    text='Hello world!' #put here your text
    def textwidth(self,x): #put here your textwidth function
        return len(x)
    
    def format( self, width=80 ):    
        _lines = ['']
        i = 0
        for word in _text.split():  
            if _textwidth(_lines[i]) + _textwidth(word) <= width:
                if _textwidth(_lines[i]) > 0:
                    _lines[i] += ' '
                    _lines[i] += word
                else:
                    i += 1
                    _lines.append(word)

d=D()
d.format()
print d.lines

I don't know if this is elegant enough for you. It works with Python 2.2,
but it has some limitations (for instance you cannot use methods
defined trough lambda functions). Moreover, in the present form, 
_x is replaced with self.x even inside strings, which is bad.
Finally, you will break pre-existing code using variables of
kind "_x".

Nevertheless, I send the script to you to show that a solution is possible,
but not recommended, since you would confused all Pythonistas if
you use that instead of self.

--- begin noself.py ---

import re,inspect

def selfexpand(cls):
    """Given a class, looks in its methods and expands identifiers starting
    with _ to self. For instance, _x --> self.x. Identifiers starting with
    __ are expanded as __x --> self._classname__x. Identifiers of the
    form __something__ are ignored. This first version is very stupid and
    does the replacement in comments (no big harm) and strings
    (potentially big harm!) too."""

    __id__=r'(\b__\w+?__\b)' #first, look at this kind of identifier
    __id  =r'\b__(\w*)'    #then, at this kind
    _id   =r'\b_([a-zA-Z_]\w*)'    #then, at this kind
    regexp=re.compile('|'.join([__id__,__id,_id]))

    def sub(match):
        i=match.lastindex; g=match.group(i)
        if   i==1: return g # do nothing
        elif i==2: return 'self._%s__%s' % (cls.__name__,g)
        elif i==3: return 'self.%s' % g
        
    def kill_initial_spaces(text):
        lines=text.splitlines(); firstline=lines[0]
        spaces=len(firstline)-len(firstline.lstrip())
        if not spaces: return text
        else: return '\n'.join([line[spaces:] for line in lines])
        
    def modify(method):
        source=kill_initial_spaces(inspect.getsource(method))
        code=regexp.sub(sub,source) # print code
        d={}; exec code+'\n' in d
        setattr(cls,method.__name__,d[method.__name__])
 
    for key,val in cls.__dict__.items():
        if inspect.isroutine(val): modify(val)

class Noself:
    class __metaclass__(type):
        "Classes who inherit from Noself automagically call selfexpand"
        def __init__(cls,name,bases,dic): selfexpand(cls)

--- end noself.py ---




More information about the Python-list mailing list