1

我正在尝试在 Python 中干净地实现 Objective-C 的类别,并找到了我的类似问题的答案。我复制了下面的代码:

类别.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给了我一些有用的信息。但我一个人做不到。

4

2 回答 2

3

不,没有办法自动做到这一点。之后您必须手动删除该名称。 category这是一个装饰器,这意味着

@category(Test)
def f():
    ...

是相同的

def f():
   ...
f = category(Test)(f)

即使category您可以从内部删除外部作用域中的名称,但这还不够,因为该名称会在装饰器执行后重新绑定。

您链接到的代码与装饰器语法的滥用有关。装饰器旨在提供一种修改或扩展它们所装饰的功能的方法,但该代码依赖于装饰器的副作用(即,将函数分配为类的方法),然后丢弃该函数。但它只能通过返回 None 来“丢弃”它,所以 None 仍然绑定到函数的名称,如您所见。

我建议您遵循对该问题的最高投票答案的建议,并简单地为您的课程分配新方法。在 Python 中没有真正需要像类别这样的“基础设施”,因为您可以随时直接向现有类添加新方法。

于 2013-03-06T07:28:52.070 回答
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
于 2013-03-06T08:42:20.100 回答