A better self

Duncan Booth duncan at NOSPAMrcp.co.uk
Mon Jul 22 05:12:53 EDT 2002


Grant Griffin <not.this at seebelow.org> wrote in
news:ah9p0o01ds at drn.newsguy.com: 

> For example:
> 
>    with self:
>       result=sin(t)*x**y+sqrt(z)  # A pretend formula
> 
> I don't know if there's a technical reason (in terms of either Python
> grammar or C implementation) why this wouldn't work, but perhaps it's
> not in Python because:
> 
>    1) explicit is better than implicit
>    2) there should be one--and preferably only one--way to do things

It isn't in Python for a variety or reasons (your two among them), but 
perhaps more because there is no way in your scheme to tell which of 
result, t, x, y, and z are members of the self instance, and which are 
global (or in result's case local) variables. Languages which require you 
to declare all the member variables in advance can get away with this sort 
of usage, but they then introduce new problems. Even in C++ it can be 
impossible to tell whether a variable in a function is implicitly 
referencing a member variable or a global of the same name.

An alternative which is proposed from time to time would be implementable:

    with self:
       result=sin(.t)*.x**.y+sqrt(.z)  # A pretend formula

This has the advantage of tagging the member variables, but is thought by 
many to reduce readability and be error prone. Perhaps someone should put 
it into a patch though so people could try it out. If Python supported this 
format you might even allow functions to default to assuming a 'with' block 
on their first argument. Then again, see your #1 above.

Of course, Python being what it is, there are ways to simulate some of what 
people want without changing the language at all. Try the code below:


----- begin magic.py -----
# How to make methods magically access member variables.
#
import new
from math import sin, sqrt

def withself(method):
    '''withself(method)
    Converts an unbound method into a method where all global variables
    are assumed to come from the instance.
    Global variables are accessible only if the instance sets
       self.__builtins__=globals()
    Builtins are not accessible unless you do:
       self.__builtins__=__builtins__
    '''
    def callwith(self, *args, **kw):
        f = new.function(method.func_code,
            self.__dict__,
            method.func_name,
            method.func_defaults or ())
        return f(self, *args, **kw)
    return callwith

class C:

    def __init__(self, x, y, z):
        self.x, self.y, self.z = x, y, z
        # Makes global variables visible to formulae
        self.__builtins__ = globals()

    def formula(self):
        return x + y - z
    formula = withself(formula)

    def updater(self):
        global x
        x += 1
    updater = withself(updater)

    def formula2(self):
        return sqrt(y*z)
    formula2 = withself(formula2)

test = C(3, 7, 2)
print test.formula()
test.updater()
print test.formula()
print test.formula2()
----- end magic.py -----

-- 
Duncan Booth                                             duncan at rcp.co.uk
int month(char *p){return(124864/((p[0]+p[1]-p[2]&0x1f)+1)%12)["\5\x8\3"
"\6\7\xb\1\x9\xa\2\0\4"];} // Who said my code was obscure?



More information about the Python-list mailing list