Seite 1 von 1

Scoping Probleme

Verfasst: Montag 1. Mai 2006, 00:00
von mitsuhiko
Ich kanns mir einfach nicht erklären:

Code: Alles auswählen

import sys
from warnings import warn


def deprecate(cls, **mapping):
    old_getattr = getattr(cls, '__getattr__', None)
    if old_getattr is None:
        old_getattr = getattr(cls, '__getattribute__', None)
    old_setattr = getattr(cls, '__setattr__', None)
    old_delattr = getattr(cls, '__delattr__', None)
    
    real_mapping = {}
    for old_name, data in mapping.iteritems():
        type_, new_name, arg_rewrites = data
        rewrites = dict([(b, a) for a, b in arg_rewrites.items()])
        if type_ == 'attribute':
            def _get(self):
                warn(DeprecationWarning('%r is deprecate, see %r' %
                                        (old_name, new_name)))
                return old_getattr(self, new_name)
        elif type_ == 'method':
            def _get(self):
                warn(DeprecationWarning('%r is deprecate, see %r' %
                                        (old_name, new_name)))
                f = old_getattr(self, new_name)
                def _wrapped(*args, **kwargs):
                    new_kwargs = {}
                    for key, value in kwargs.iteritems():
                        if key in rewrites:
                            new_kwargs[key] = kwargs[rewrites[key]]
                        else:
                            new_kwargs[key] = kwargs[key]
                    return f(*args, **new_kwargs)
                _wrapped.__name__ = f.__name__
                _wrapped.__doc__ = f.__doc__
                return _wrapped
        else:
            raise AssertionError('invalid mapper value %r' % type_)
        def _set(self, value):
            warn(DeprecationWarning('%r is deprecate, see %r' %
                                    (old_name, new_name)))
            old_setattr(self, new_name, value)
        def _del(self):
            warn(DeprecationWarning('%r is deprecate, see %r' %
                                    (old_name, new_name)))
            old_delattr(self, new_name)
        real_mapping[old_name] = property(_get, _set, _del,
                                         'deprecate method %r, see %r' %
                                         (old_name, new_name))
    
    def _getattr(self, attr):
        if attr in real_mapping:
            t = real_mapping[attr]
            return t.__get__(self)
        return old_getattr(self, attr)
        
    def _setattr(self, attr, value):
        if attr in real_mapping:
            t = real_mapping[attr]
            t.__set__(self, value)
        old_setattr(self, attr, value)
        
    def _delattr(self, attr):
        if attr in real_mapping:
            t = real_mapping[attr]
            t.__del__(self, value)
        old_delattr(self, attr, value)
    
    cls.__getattr__ = _getattr
    cls.__setattr__ = _setattr
    cls.__delattr__ = _delattr

deprecate.method = lambda name, **args: ('method', name, args)
deprecate.attribute = lambda name: ('attribute', name, {})


def test():
    """
    Test Cases.
    """
    
    class MyClass(object):

        def __init__(self):
            self._my_attribute = 'default name'

        def my_method(self, my_args=None):
            if my_args is None:
                name = self._my_attribute
            else:
                name = my_args
            return 'Hello %s!' % name

    deprecate(MyClass,
        myMethod=deprecate.method('my_method', myArgs='my_args'),
        myAttribute=deprecate.attribute('_my_attribute')
    )

    obj = MyClass()
    print '1', obj.myAttribute
    print '2', obj._my_attribute
    print '3', obj.my_method()
    print '4', obj.myMethod()


if __name__ == '__main__':
    test()
Ausgabe:

Code: Alles auswählen

blackbird@volverine:~/Developement/area51$ frog apichange.py
apichange.py:23: DeprecationWarning: 'myMethod' is deprecate, see 'my_method'
  warn(DeprecationWarning('%r is deprecate, see %r' %
1 <bound method MyClass.my_method of <__main__.MyClass object at 0xb7cfcc8c>>
2 default name
3 Hello default name!
apichange.py:28: DeprecationWarning: 'myMethod' is deprecate, see 'my_method'
  warn(DeprecationWarning('%r is deprecate, see %r' %
4 Hello default name!
Warum bekomm ich am Anfang "'myMethod' is deprecate, see 'my_method'", wo ich eindeutig auf "myAttribute" zugreife? :shock:

Verfasst: Montag 1. Mai 2006, 07:55
von mitsuhiko
Hmmm. Schon klar. Eine For Schleife ist kein eigener Frame. Das heißt wenn ich eine Funktion proxy(old_name, data) oder sowas mach geht das.

Damit gibts bis zu 3 verschachtelte Funktionen. AUA

Verfasst: Montag 1. Mai 2006, 11:23
von mitsuhiko
Für Interessierte, der Sourcecode ist hier: http://trac.pocoo.org/repos/sandbox/apichange.py