是否可以檢查一個函數/方法,看它是否可以用作裝飾器?在那裏它遵循裝飾器包裝其他功能並返回一個可調用的常用方法?具體來說,我期待驗證第三方代碼。如何查看方法是否爲裝飾器?
回答
通過應用疑似裝飾,捕獲異常,然後測試結果是否包含__call__
方法,可以產生一個猜測,一個給定的調用是一個裝飾或沒有。但這只是一個猜測,而不是一個保證。由於Python語言的動態類型化特性以及CPython解釋器中內置函數的特殊處理,除此之外,我不相信你所希望的一般可能。無法通過編程來判斷可調用對象是否將另一個可調用對象接受爲參數,或者返回值的類型是什麼類型。另外,在CPython中,對於在C中實現的函數,甚至不能檢查可調用函數以查看它接受的參數數量。
「裝飾者」一詞可以理解爲不同的意思。定義它的一種方法是,裝飾器是可接受單個(可調用)參數並返回可調用對象的任何可調用對象。
請注意,我甚至沒有在這個定義中使用「功能」一詞;這樣做實際上是不正確的。事實上,一些常用的裝飾有奇怪的特性:
- 內置
classmethod
和staticmethod
裝飾返回描述對象,而不是功能。 - 由於語言版本2.6你可以裝飾類,而不僅僅是函數和方法。
- 任何包含
__init__(self, somecallable)
方法和__call__(self, *args, **kwargs)
方法的類都可以用作裝飾器。
謝謝 - 你的聲明,一個裝飾器可以「可調用,接受一個可調參數並返回一個可調參數」將是我測試的基礎,應該足以進行驗證,因爲這就是他們應該在第三方代碼中創建。然而,從複雜性來看,我只是試着提供一些不錯的錯誤信息。 :d – 2012-03-22 12:17:26
我從來沒有做過這樣的事情,但一般來說python依賴於「鴨子打字」在這種情況下。所以你可以試着裝飾一個虛擬函數,看看是否可以返回一個可調用函數。
由於在Python中沒有標準化的裝飾器,所以沒有真正的方法來判斷一個函數是否是裝飾器,除非你知道你正在尋找的裝飾器的一些東西。
如果裝飾器在你的控制之下,你可以添加一個標記來表明它是一個裝飾的功能。否則,沒有真正的統一方式來做到這一點。藉此示例如:
def decorator(func):
return g
@decorator
def f()
pass
def g():
pass
在上述例子中,在運行時,f和g將是相同的,並且沒有告訴兩個分開的方式。
不,這是不可能的。可能不是檢查f
是否是裝飾器,你應該考慮爲什麼你需要檢查?
如果你期待一些具體的裝飾,可以直接查詢,如果你想要一些特定的行爲/方法/屬性,你可以檢查
如果你想檢查是否存在贖回f
可以作爲裝飾,您可以通過傳遞一些虛函數來測試裝飾器行爲,但通常它可能無法正常工作,或者對於不同的輸入具有不同的行爲。
這裏是一個這樣的幼稚檢查:
def decorator1(func):
def _wrapper(*args, **kwargs):
print "before"
func(*args, **kwargs)
print "after"
return _wrapper
def dummy_func(): pass
out_func = decorator1(dummy_func)
if callable(out_func) and dummy_func != out_func:
print "aha decorated!"
'你可以通過傳遞一些虛擬函數直接檢查'??不是真的......你不能說出它會用它的論點來做什麼! – katrielalex 2012-03-20 21:41:32
@katrielalex是的,爲什麼一般答案是否定的,但如果你知道裝飾者應該做什麼,你可以通過使用它來檢查行爲 – 2012-03-20 21:44:19
任何可調用用的參數的權數可被用作裝飾。請記住,
@foo
def bar(...):
是正是一樣
def bar(...):
...
bar = foo(bar)
當然,因爲foo
可以返回什麼,你有沒有檢查功能是否已裝修完畢與否的方式。雖然foo
可能很好,並留下印記,但它沒有義務這樣做。
如果你給出一些Python代碼,並要找出所有裝飾的東西,你可以通過分析代碼轉換成抽象語法樹,然後遍歷樹尋找裝飾功能,這樣做。下面是一個例子,存儲裝飾器的.id
。顯然,如果你願意,你可以存儲ast
對象。
>>> class DecoratorFinder(ast.NodeVisitor):
... def __init__(self, *args, **kwargs):
... super(DecoratorFinder, self).__init__(*args, **kwargs)
... self.decorators = set()
...
... def visit_FunctionDef(self, node):
... self.decorators.update(dec.id for dec in node.decorator_list)
... self.generic_visit(node)
...
>>> finder = DecoratorFinder()
>>> x = ast.parse("""
... @dec
... def foo():
... pass
... """)
>>> finder.visit(x)
>>> finder.decorators
set(['dec'])
其實只有可能至少需要一個位置參數的可調用... – 2012-03-20 22:19:16
@Niklas你當然是正確的=) – katrielalex 2012-03-20 22:20:47
- 1. 角方法裝飾器如何工作?
- 2. 使用類作爲方法裝飾器
- 3. 生成器裝飾器是否存在?
- 4. 裝飾類裝飾類方法
- 5. 裝飾模式問題 - 如何調用嵌套裝飾方法?
- 6. 裝飾python類方法,如何將實例傳遞給裝飾器?
- 7. 從裝飾器訪問擁有裝飾方法的類
- 8. 使用draper裝飾器時的裝飾方法列表
- 9. 裝飾裝飾器
- 10. Lua是否支持裝飾器?
- 11. 如何裝飾類內的方法?
- 12. 重載裝飾器的方法
- 13. Django裝飾器,添加方法到WSGIRequest
- 14. python2中的類方法鉤裝飾器
- 15. 最終方法的Java類裝飾器
- 16. Python實例方法上的裝飾器
- 17. python裝飾器是如何定義的?
- 18. 如何查看日期是否爲零?
- 19. 類作爲裝飾類方法
- 20. 檢查一個Python函數是否用特定的修飾器裝飾
- 21. 檢查一個函數是否有裝飾器
- 22. Python裝飾器,檢查函數是否被調用之前
- 23. Python - 是否有一個裝飾器列表的地方?
- 24. 是否可以在Typescript中修飾裝飾器?
- 25. 滾動查看器中的錯誤裝飾器
- 26. 單元測試庫如何確定是否運行裝飾方法?
- 27. 如何使用裝飾器?
- 28. 裝飾父類方法
- 29. 裝飾方法在Python
- 30. 在Python中裝飾方法
你的意思是*可以用作裝飾器*或*用作裝飾器的某處*?雖然第一個可能非常困難,但如果不是不可能一般解決,第二個可能實際上是可行的。 – 2012-03-20 21:19:54
或者你問函數是否被修飾? – forivall 2012-03-20 21:36:08
@NiklasB。對不起 - 澄清了這個問題。 – 2012-03-20 22:04:42