【发布时间】:2021-07-22 20:54:08
【问题描述】:
为了在 Python 中尽可能高效地编写优先级队列的面向对象实现,我遇到了一个有趣的行为。以下代码工作正常
from heapq import heappush
class PriorityQueue(list):
__slots__ = ()
def push(self, item):
heappush(self, item)
但是,我真的不想为调用heappush 编写包装方法,因为调用该函数会产生额外的开销。我推断由于heappush 签名使用list 作为第一个参数,同时将push 类属性与heappush 函数别名,后者成为一个成熟的类实例方法。但是,我的假设结果是错误的,下面的代码给出了错误。
from heapq import heappush
class PriorityQueue(list):
__slots__ = ()
push = heappush
PriorityQueue().push(0)
# TypeError: heappush expected 2 arguments, got 1
但是转到cpython heapq 源代码,只需将heappush 实现复制到范围并应用相同的逻辑即可。
from heapq import _siftdown
def heappush(heap, item):
"""Push item onto heap, maintaining the heap invariant."""
heap.append(item)
_siftdown(heap, 0, len(heap) - 1)
class PriorityQueue(list):
__slots__ = ()
push = heappush
pq = PriorityQueue()
pq.push(0)
pq.push(-1)
pq.push(3)
print(pq)
# [-1, 0, 3]
- 第一个问题:为什么会这样?
Python如何决定哪个函数适合绑定为实例方法,哪个不适合? - 第二个问题:
cpython/Lib/heapq.py中的heappush与heapq模块中的实际heappush有什么区别?它们实际上是不同的,因为以下代码给出了错误
from dis import dis
from heapq import heappush
dis(heappush)
# TypeError: don't know how to disassemble builtin_function_or_method objects
- 第三个问题:如何强制
Python绑定原生heappush作为实例方法?一些元类魔法?
谢谢!
【问题讨论】:
标签: python oop methods metaclass python-3.9