2013-03-06 5 views
1

Я пытаюсь выполнить чистый объект Objective-C в Python и нашел 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 предоставил мне полезную информацию. Но я не мог сделать это сам.

ответ

3

Нет, автоматизировать это невозможно. После этого вам придется вручную удалить имя. category здесь декоратор, что означает, что

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

такая же, как

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

Даже если внутри category, вы можете удалить имя во внешней области видимости, это не было бы достаточно , потому что это имя отскок после декоратор выполняет.

Код, который вы связывали с границами при злоупотреблении синтаксисом декоратора. Декораторы призваны обеспечить способ изменения или расширения функции, которую они украшают, но этот код основывается на побочных эффектах декоратора (а именно, назначении функции как метода класса), а затем отбрасывает функцию. Но он может только «отказаться» от него, возвращая None, поэтому None остается привязанным к имени функции, как вы видели.

Я бы порекомендовал вам следовать совету наивысшего голоса по этому вопросу и просто назначить новые методы для своих классов. Нет никакой реальной потребности в «инфраструктуре», подобной категориям на Python, поскольку вы можете просто добавлять новые методы к существующим классам, когда захотите.

+0

Благодарим за сообщение. Я изменю свой план и реализую их более питоническим способом! – user2100702

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 
Смежные вопросы