Inserting class namespace into method scope

Duncan Booth duncan.booth at invalid.invalid
Sat Nov 20 17:24:45 CET 2010


Steven D'Aprano <steve at REMOVE-THIS-cybersource.com.au> wrote:

> But in this specific case I have reasons for wanting to avoid both of
> the normal behaviours. Do not judge me, please accept that I have a
> good reason for wanting this, or at least allow me to shoot myself in
> the foot this way *wink*. In Python 3, is there some way to get this
> unusual behaviour?
> 
Sounds more like you want a mercy killing rather than just shooting in 
the foot.

However, if I had taken sufficient illegal substances to want to do 
this, I would decorate the function with an attribute to indicate that I 
want it messed up, and then use a metaclass to create a new function 
from the original one but with the class namespace in place of the 
__globals__ attribute. I think you need to do it in a metaclass because 
once the class is created you just have a dictproxy and you need a real 
dict as the globals argument to the function constructor.

The limitations will be that the resulting method cannot access any 
globals and also any changes to the class namespace won't be visible 
inside the function (since the class's dictproxy is a copy of the dict).

from types import FunctionType
class WeirdClass(type):
    def __new__(cls, name, bases, classdict):
        for attrname, attribute in classdict.items():
            if getattr(attribute, '_useclassglobals', False):
                classdict[attrname] = FunctionType(attribute.__code__,
                    classdict, attribute.__name__,
                    attribute.__defaults__, attribute.__closure__)
        result = type.__new__(cls, name, bases, classdict)
        return result

def classglobals(f):
    f._useclassglobals = True
    return f


x = "outside"

class Magic(metaclass=WeirdClass):
    x = "inside"
    @classglobals
    def method(self):
        return x

m = Magic()
print(m.method()) # prints 'inside'
Magic.x = "new value"
print(m.method()) # still prints 'inside'


-- 
Duncan Booth http://kupuguy.blogspot.com



More information about the Python-list mailing list