2013-03-06 66 views
1

我在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給了我一些有用的信息。但我自己無法做到。

回答

3

不,沒有辦法自動做到這一點。之後您將不得不手動刪除名稱。 category這裏是一個裝飾,這意味着

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

相同

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

即使從裏面category,你可以刪除在外部範圍的名稱,這是不夠的,因爲裝飾者執行之後這個名字被反彈。

您通過濫用裝飾器語法鏈接到邊界的代碼。裝飾器旨在提供一種方法來修改或擴展它們裝飾的功能,但代碼依賴裝飾器的副作用(即將函數分配爲類的方法),然後丟棄該函數。但是它只能通過返回None來「丟棄」它,所以None仍然與函數的名稱綁定在一起,如您所見。

我會建議你遵循對這個問題,投票最高的答案的建議,並簡單地分配新方法的類。對於類似Python的「基礎結構」來說,並不是真的需要,因爲只要你願意,你可以直接向現有的類添加新的方法。

+0

謝謝你給我一個答案。我會改變我的計劃,並以更加pythonic的方式實施它們! – user2100702 2013-03-06 14:43:23

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 
相關問題