我有一个元类,只是在我的模块的类中附加一个前缀。到目前为止一直很好,问题是我想删除调用元类的类的定义。例如,如果 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
解决问题的额外学分!
答案 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'>