我正在尝试在Python中干净地实现Objective-C的类别,并发现this answer类似于我的问题。我复制了以下代码:
categories.py
class category(object):
def __init__(self, mainModule, override = True):
self.mainModule = mainModule
self.override = override
def __call__(self, function):
if self.override or function.__name__ not in dir(self.mainModule):
setattr(self.mainModule, function.__name__, function)
但我不想浪费命名空间。 通过使用这个“类别”,仍然存在一个变量NoneType对象,如下所示:
>>> from categories import category
>>> class Test(object):
... pass
...
>>> @category(Test)
... def foobar(self, msg):
... print msg
...
>>> test = Test()
>>> test.foobar('hello world')
hello world
>>> type(foobar)
<type 'NoneType'>
>>>
我希望它像下面一样
>>> from categories import category
>>> class Test(object):
... pass
...
>>> @category(Test)
... def foobar(self, msg):
... print msg
...
>>> test = Test()
>>> test.foobar('hello world')
hello world
>>> type(foobar)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'foobar' is not defined
>>>
无论如何都要自动将其删除,如下所示?
def __call__(self, function):
if self.override or function.__name__ not in dir(self.mainModule):
setattr(self.mainModule, function.__name__, function)
del(somewhere.function.__name__)
我发现sys._getframe
给了我一些有用的信息。但我不能自己做。
答案 0 :(得分:3)
不,没有办法自动做到这一点。之后您必须手动删除名称。 category
这里是一个装饰器,意思是
@category(Test)
def f():
...
与
相同def f():
...
f = category(Test)(f)
即使从category
内部删除了外部作用域中的名称,也是不够的,因为在装饰器执行后,该名称会被反弹。
您滥用装饰器语法链接到边框的代码。装饰器旨在提供修改或扩展它们所装饰的函数的方法,但该代码依赖于装饰器的副作用(即,将函数指定为类的方法),然后丢弃该函数。但它只能通过返回None来“丢弃”它,所以没有像你看到的那样仍然绑定到函数的名称。
我建议您按照该问题的最高投票答案的建议,并简单地为您的班级分配新方法。 Python中没有真正需要类似“基础结构”的类别,因为您可以随时直接向现有类添加新方法。
答案 1 :(得分:0)
虽然我完全同意BrenBarn的说法,但您可以将功能删除拆分为后续步骤。问题是在装饰器执行后,重新分配变量。所以你不能在装饰器本身内执行删除。
然而,您可以记住这些功能,并在稍后将其从模块中删除。
class category(object):
functions = []
def __init__(self, mainModule, override = True):
self.mainModule = mainModule
self.override = override
def __call__(self, function):
if self.override or function.__name__ not in dir(self.mainModule):
setattr(self.mainModule, function.__name__, function)
self.functions.append((inspect.getmodule(function), function.__name__))
return self.dummy
@staticmethod
def dummy():
pass
@classmethod
def cleanUp(cls):
for module, name in cls.functions:
if hasattr(module, name) and getattr(module, name) == cls.dummy:
delattr(module, name)
cls.functions = []
此category
类型将记住它所装饰的函数,并存储它们所属的名称和模块,以便稍后进行清理。装饰器还返回一个特殊的虚函数,以便清理可以确保稍后不重新赋值变量。
>>> class Test(object): pass
>>> @category(Test)
def foobar(self, msg):
print(msg)
>>> @category(Test)
def hello_world(self):
print('Hello world')
>>> test = Test()
>>> test.foobar('xy')
xy
>>> test.hello_world()
Hello world
>>> type(foobar)
<class 'function'>
>>> type(hello_world)
<class 'function'>
>>> category.cleanUp()
>>> type(foobar)
Traceback (most recent call last):
File "<pyshell#26>", line 1, in <module>
type(foobar)
NameError: name 'foobar' is not defined
>>> type(hello_world)
Traceback (most recent call last):
File "<pyshell#27>", line 1, in <module>
type(hello_world)
NameError: name 'hello_world' is not defined