我想演示Python中的裝飾器對一些人的用處,並且以一個簡單的例子失敗:考慮兩個函數(爲了簡單起見,沒有參數)f
和g
。 可以將它們的和f + g定義爲返回f()+ g()的函數。當然,函數的加,減等等通常沒有定義。但是編寫一個將每個函數轉換爲可添加函數的裝飾器很容易。爲什麼這個「可操作函數」的python實現失敗?
現在我想要有一個裝飾器,可以將任何函數轉換爲「可操作」的函數,也就是說,對於標準模塊operator
中的任何操作符,所描述的函數都具有相同的功能。我的實現看起來如下:
import operator
class function(object):
def __init__(self, f):
self.f = f
def __call__(self):
return self.f()
def op_to_function_op(op):
def function_op(self, operand):
def f():
return op(self(), operand())
return function(f)
return function_op
binary_op_names = ['__add__', '__and__', '__div__', '__eq__', '__floordiv__', '__ge__', '__gt__', '__le__', '__lt__', '__mod__', '__mul__', '__ne__', '__or__', '__pow__', '__sub__', '__truediv__', '__xor__']
for name in binary_op_names:
type.__setattr__(function, name, op_to_function_op(getattr(operator, name)))
讓我們進行一個小測試,看看它的工作原理:
@function
def a():
return 4
def b():
return 7
c = a + b
print c()
print c() == operator.__add__(4, 7)
輸出:
11
True
這是我的一些試驗後得到的最終版本。 現在讓我們做兩個小的,不相關的修改來看看有什麼我嘗試過:
首先:在binary_op_names
定義中,方括號改爲圓括號。突然,(對我來說)完全無關的錯誤消息傳出:
Traceback (most recent call last):
File "example.py", line 30, in <module>
c = a + b
TypeError: unsupported operand type(s) for +: 'function' and 'function'
哪裏這個來自?
二:寫op_to_function_op
作爲lambda表達式:
op = getattr(operator, name)
type.__setattr__(function, name, lambda self, other: function(lambda: op(self(), other())))
執行稍微複雜的測試案例:
@function
def a():
return 4
def b():
return 7
c = a + b
print c()
print c() == operator.__add__(4, 7)
print c() == operator.__xor__(4, 7)
輸出:
3
False
True
這看起來對我像範圍泄漏,但我再次不不明白爲什麼會發生這種情況。
型.__ setattr__似乎做邪惡的東西..不要不知道是什麼。元組列表的東西真的很奇怪。如果你改變類型。__setattr__ setattr一切似乎工作。 – mkorpela
應用於斐波納契序列和其他緩存友好問題的典型「memoize」裝飾器可能是更好的應用程序來演示裝飾器。 – Daenyth
這個元組問題似乎是一個令人髮指的bug。我看到了同樣的行爲。關於'name'的所有內容都會檢查出來,但是'type .__ setattr__'不起作用。 – Nate