所以我正在为自己的方便编写一个简单的堆数据结构,并意识到要正确地执行它,我需要检查是否有许多参数是可以清除的,以便heapq操作正常工作。
import heapq
def hashable(func):
def hidden(self, item):
try:
hash(item)
func(self, item)
except TypeError as e:
raise e
hidden.__doc__ = func.__doc__
return hidden
class heap(object):
def __init__(self, heap=[]):
self.heap = heap
heapq.heapify(heap)
def pop(self):
'''
Pop and return the smallest item from the heap, maintaining the heap
invariant. If the heap is empty, IndexError is raised.
'''
return heapq.heappop(self.heap)
@hashable
def push(self, item):
'''
Push the value item onto the heap, maintaining the heap invariant.
'''
return heapq.heappush(self.heap, item)
@hashable
def pushpop(self, item):
'''
Push item on the heap, then pop and return the smallest item from
the heap.
The combined actions runs more efficiently than heappush()
followed by a separate called to heappop().'''
heapq.heappushpop(self.heap, item)
@hashable
def poppush(self, item):
'''
Pop and return the smallest item from the heap, then push item on
the heap.
The combined actions runs more efficiently than heappop()
followed by a separate called to heappush().'''
heapq.heapreplace(self.heap, item)
def __setitem__(self, i, y):
self.heap[self.heap.index(i)] = y
heapq.heapify(self.heap)
def __len__(self):
return len(self.heap)
def __iter__(self):
while self.heap:
yield self.pop()
我遇到的问题是 setitem 。虽然 setitem 也要求'y'可以清洗,如果我用hashable装饰它,它只能用一个参数。
显而易见的解决方案就是改变hashable的隐藏功能来接受'self'和'* args',但是我很愿意使用这样的解决方案,因为它不漂亮并且只会使代码复杂化。
我的问题是,是否有可能重写代码以便隐藏采用传递给装饰器的函数的参数?
答案 0 :(得分:3)
为什么让hashable
成为装饰者?为什么不让它成为一个你可以调用的函数,它会正常引发异常,然后只是在函数体中调用它,将它传递给你要检查的东西?
事实上,从您编写装饰器的方式来判断,hash()
已经完全没有了?为什么不,而不是这个:
@hashable
def push(self, item):
'''
Push the value item onto the heap, maintaining the heap invariant.
'''
return heapq.heappush(self.heap, item)
写这个?
def push(self, item):
'''
Push the value item onto the heap, maintaining the heap invariant.
'''
hash(item)
return heapq.heappush(self.heap, item)
如果您这样做,那么它会解决您的__setitem__
问题:
def __setitem__(self, i, y):
hash(i), hash(y)
self.heap[self.heap.index(i)] = y
heapq.heapify(self.heap)
也就是说,关于“使用相同的args返回一个函数”的问题 - 完全 *args
和**kwargs
语法是为什么设计的,所以我'我不确定你为什么认为它“不漂亮”或“使代码复杂化”。
答案 1 :(得分:1)
首先,我会采取另一种方式:
def hashable(func):
def hidden(self, item):
try:
hash(item)
except TypeError as e:
raise e
else:
return func(self, item) # return might be important!
hidden.__doc__ = func.__doc__
return hidden
它确实完全相同(但只是因为except
套件“没有”),但它向人类读者显示了不同的意图:你对func()中发生的异常不感兴趣。 (或者甚至省略try
... except
... else
而只是做
hash(item)
return func(...)
这也会引起错误,并在成功时返回。
此外,包装器应该return
func()
的返回值才能真正灵活。
然后你可以写一个hashable2()
,它用2个参数做同样的事情。或者你甚至可以写一个“间接装饰者”,我。即返回装饰器的函数。所以你可以使用
@hashable(2)
def ...
甚至
@hashable(1, 2)
def ...
以指示应该可以清除的参数索引。
答案 2 :(得分:0)
我同意Amber的观点,在这种情况下,直接使用hash
可能更简单。
但是对于您的问题的一般情况,请查看wraps
标准库模块中的functools
装饰器。你可以这样做:
def hashable(func):
@functools.wraps(func)
def hidden(self, item):
...
return hidden
这意味着从func
复制返回的funcion的名称,docstring和模块。这可能不足以让标签完成,但它至少有助于包装函数看起来更像原始。