如何在创建后立即从全局变量中删除一个类?

时间:2014-02-20 20:14:30

标签: python metaclass

我有一个元类,只是在我的模块的类中附加一个前缀。到目前为止一直很好,问题是我想删除调用元类的类的定义。例如,如果 A 类以 PrefixA 作为前缀,我将以我的全局变量上的两个类结束,但我只想要 PrefixA 。为了实现我的目标,我正在做这样的事情:

class PrefixChanger(type):

    prefix = 'Prefix'
    to_delete = []

    def __new__(cls, clsname, bases, attrs):
        new_cls = type.__new__(cls,cls.prefix+clsname,bases,attrs)
        globals()[cls.prefix+clsname] = new_cls
        cls.to_delete.append(clsname)
        return new_cls

    @classmethod
    def do_clean(cls):
        gl = globals() 
        for name in cls.to_delete:            
            del gl[name]                

class A(object):
    __metaclass__ = PrefixChanger        

class B(PrefixA):
    pass

PrefixChanger.do_clean()

这种方法的问题是我必须将最后一行PrefixChanger.do_clean()放在使用我的元类的每个模块的末尾。

那么,有没有办法以正确的方式做到这一点?我的意思是元类(或某种黑魔法)尽快从全局变量中删除不需要的类(可能就在他们的定义之后)。

我对以这种方式完成任务感兴趣,但也欢迎使用其他方法做一些建议。

我的解决方案也解决了这个问题:

class B(object):
    class C(object):
        __metaclass__ = PrefixChanger

解决问题的额外学分!

2 个答案:

答案 0 :(得分:1)

可能性3

启动一个阻塞队列并从其引用者中删除类的线程。 您可以使用gc模块获取引用对象。 gc.get_referrers

Muhaha

### License: You may only use this code if it is for the good of humanity.
### Any copy of the code requires this license to be copied with it.

>>> class T(type):
    prefix = 'meep'
    def __new__(cls, name, bases, attrs):
        new_cls = type.__new__(cls, cls.prefix+name,bases,attrs)
        globals()[cls.prefix+name] = new_cls # interesting
        l = []
        import threading
        def t():
            import gc
            while 1:
                for ref in gc.get_referrers(l):
                    try: del ref[name];break
                    except:pass
        threading.Thread(target = t).start()
        return l


>>> class C(object):
    __metaclass__ = T


>>> C

Traceback (most recent call last):
  File "<pyshell#30>", line 1, in <module>
    C
NameError: name 'C' is not defined
>>> meepC
<class '__main__.meepC'>

不可能性2

不要在其中放置一个类,然后您不需要删除它:

class PrefixChanger(type):
    # ...

    def __new__(cls, clsname, bases, attrs):
        # ...
        return None

不可能性1 <怎么样

PrefixChanger('A', (object,), {})

您无需删除它。我的意思是..你的课程没有内容,但如果应该有,那么这当然不是一个选择。

答案 1 :(得分:1)

在创建之后立即删除它们的最直接的方法是在创建之后立即执行 - 似乎没有任何类或模块创建“钩子”(软件拦截)提供隐式执行此操作的方式。

以下是权衡:它不需要在每个模块的末尾调用do_clean()函数,而是必须在每个类定义之后放置对函数的调用。 /> 另一方面,这可能不比添加

更糟糕
    __metaclass__ = PrefixChanger
每个班级定义中的

语句......

import textwrap  # to help make the exec code more readable

def Prefix(cls, prefix='Prefix'):
    exec(textwrap.dedent('''\
        global {prefix}{classname}
        {prefix}{classname} = {classname}
        {prefix}{classname}.__name__ = "{prefix}{classname}"
        del globals()["{classname}"]
        '''.format(prefix=prefix, classname=cls.__name__))
    )

class A(object):
    pass
Prefix(A)

class B(PrefixA):
    pass
Prefix(B)

if __name__ == '__main__':
    try:
        print 'A:', A
    except NameError:
        print 'there\'s nothing named "A"'
    else:
        print 'error: there shouldn\'t be anything named "A"'

    print 'PrefixA:', PrefixA
    print 'PrefixB:', PrefixB

输出:

A: there's nothing named "A"
PrefixA: <class '__main__.PrefixA'>
PrefixB: <class '__main__.PrefixB'>