Getting the block of commands that are to be executed in the with statement

为君一笑 提交于 2019-11-27 23:20:35

Try this.

import sys 
class MyNameSpace(object):
    def __init__(self,ns):
        self.ns = ns
    def __enter__(self):
        globals().update(self.ns)
    def __exit__(self, exc_type,exc_value,traceback):
        self.ns.update(sys._getframe(1).f_locals)

my_dict = {'a':3, 'b':2} 
with MyNameSpace(my_dict) as ns:
    print(a) # Should print 3
    x = 5 # When the block finishes, my_dict['x'] should now be 5 

print(my_dict['x'])

Here is something similar I tried a few months ago:

import sys
import inspect
import collections

iscallable = lambda x: isinstance(x, collections.Callable)

class Namespace(object):
    def __enter__(self):
        """store the pre-contextmanager scope"""
        f = inspect.currentframe(1)
        self.scope_before = dict(f.f_locals)
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        """determine the locally declared objects"""
        f = inspect.currentframe(1)
        scope_after = dict(f.f_locals)
        scope_context = set(scope_after) - set(self.scope_before)

        # capture the local scope, ignoring the context manager itself
        self.locals = dict(
            (k, scope_after[k]) for k in scope_context if not isinstance(scope_after[k], self.__class__)
        )

        for name in self.locals:
            obj = scope_after[name]
            if iscallable(obj):
                # closure around the func_code with the appropriate locals
                _wrapper = type(lambda: 0)(obj.func_code, self.locals)
                self.__dict__[name] = _wrapper
                # update locals so the calling functions refer to the wrappers too
                self.locals[name] = _wrapper
            else:
                self.__dict__[name] = obj

            # remove from module scope
            del sys.modules[__name__].__dict__[name]

        return self

with Namespace() as Spam:
    x = 1
    def ham(a):
        return x + a      
    def cheese(a):
        return ham(a) * 10

It uses inspect to modify locals while within the context manager and then to re-assign back to the original values when done.

It's not perfect - I can't remember where it hits issues, but I'm sure it does - but it might help you get started.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!