为啥我的类不继承其基类中定义的方法?

Posted

技术标签:

【中文标题】为啥我的类不继承其基类中定义的方法?【英文标题】:Why isn't my class inheriting a method defined in its base class?为什么我的类不继承其基类中定义的方法? 【发布时间】:2021-01-01 07:06:58 【问题描述】:

我正在研究 Goodrich 等人的数据结构和算法,但我无法理解为什么下面的代码有错误。具体来说,这是一个未排序的优先级队列的实现。下面的代码包含四个类:双向链接位置列表的基类、位置列表、优先级队列的基类和未排序的优先级队列。在类定义的最后,我创建了一个未排序的优先级队列,向其中添加三个键/值,然后尝试找到最小值。但是,当调用方法“_find_min”时,会出现一个错误,指出“UnsortedPriorityQueue 没有属性 'is_empty'”。但是为什么“is_empty”没有从它的基类继承呢?

class _DoublyLinkedBase:
    
    class _Node:
        __slots__ = '_element', '_prev', '_next'

        def __init__(self, _element, _prev, _next):
            self._element = _element
            self._prev = _prev
            self._next = _next

    def __init__(self):
        self._header = self._Node(None, None, None)
        self._trailer = self._Node(None, None, None)
        self._header._next = self._trailer
        self._trailer._prev = self._header
        self._size = 0

    def __len__(self):
        return self._size

    def is_empty(self):
        return self._size == 0

    def _insert_between(self, e, predecessor, successor):
        newest = self._Node(e, predecessor, successor)
        predecessor._next = newest
        successor._prev = newest
        self._size += 1
        return newest

    def _delete_node(self, node):
        predecessor = node._prev
        successor = node._next
        predecessor._next = successor
        successor._prev = predecessor
        self._size -= 1
        element = node._element
        node._prev = node._next = node._element = None #Depreciate node
        return element
        
        
        
        
class PositionalList(_DoublyLinkedBase):

    class Position:

        def __init__(self, container, node):
            self._container = container
            self._node = node

        def element(self):
            return self._node._element

        def __eq__(self, other):
            return type(other) is type(self) and other._node is self._node

        def __ne__(self, other):
            return not(self == other)

    def _validate(self, p):
        if not isinstance(p, self.Position):
            raise TypeError( 'p must be proper Position type' )
        if p._container is not self:
            raise ValueError( 'p does not belong to this container' )
        if p._node._next is None: # convention for deprecated nodes
            raise ValueError( 'p is no longer valid' )
        return p._node

    def _make_position(self, node):
        if node is self._header or node is self._trailer:
            return None
        else:
            return self.Position(self, node)

    def first(self):
        return self._make_position(self._header._next)

    def last(self):
        return self._make_position(self._trailer._prev)

    def before(self, p):
        node = self._validate(p)
        return self._make_position(node._prev)

    def after(self, p):
        node = self._validate(p)
        return self._make_position(node._next)

    def __iter__(self):
        cursor = self.first()
        while cursor is not None:
            yield cursor.element()
            cursor = self.after(cursor)

    def _insert_between(self, e, predecessor, successor):
        node = super()._insert_between(e, predecessor, successor)
        return self._make_position(node)

    def add_first(self, e):
        return self._insert_between(e, self._header, self._header._next)

    def add_last(self, e):
        return self._insert_between(e, self._trailer._prev, self._trailer)

    def add_before(self, p, e):
        original = self._validate(p)
        return self._insert_between(e, original._prev, original)

    def add_after(self, p, e):
        original = self._validate(p)
        return self._insert_between(e, original, original._next)

    def delete(self, p):
        original = self._validate(p)
        return self._delete_node(orignal)

    def replace(self, p, e):
        original = self._validate(p)
        old_value = original._element
        original._element = e
        return old_value
        
class PriorityQueueBase:
    class _Item:
        __slots__ = '_key', '_value'
        def __init__(self, k, v):
            self._key = k
            self._value = v
        def __lt__(self, other):
            return self._key < other._key #Compare items based on keys
        def is_empty(self):
            return len(self) == 0
        
class UnsortedPriorityQueue(PriorityQueueBase):
    #_data is a positional list
    def _find_min(self): #Nonpublic utility, means it shouldn't be accessed->
        if self.is_empty():                           #-> outside of the class
            raise Exception('Priority Queue is empty.')
        small = self._data.first() #This is a positional list
        walk = self._data.after(small)
        while walk is not None:
            if walk.element() < small.element():
                small = walk
            walk = self._data.after(walk)
        return small
    def __init__(self):
        self._data = PositionalList()
    def __len__(self):
        return len(self._data)
    def add(self, key, value):
        #PositionalList elements are _Items.
        self._data.add_last(self._Item(key, value))
    def min(self):
        p = self._find_min()
        item = p.element()
        #PositionalList elements are _Items.
        return (item._key, item._value)
    def remove_min(self):
        p = self._find_min()
        item = self._data.delete(p)
q = UnsortedPriorityQueue()
q.add(1, 'a')
q.add(2, 'b')
q.add(3, 'c')
q.min()

【问题讨论】:

我不确定我是否理解您的问题。我只是想理解书中的数据结构,这就是代码的呈现方式。这里使用内部类有什么特别之处吗? 因为基类没有实现is_empty。您的基类PriorityQueueBase 有一个属性_Item。你知道,像这样的嵌套类通常不是你在 Python 中看到的模式。你可以让它工作,但它是单调的。注意:您的代码包含 七个 类,而不是四个。无论如何,这似乎只是无意的缩进。 我以不同的方式阅读您的代码,不明白您想要达到的目标。似乎你犯了一个让我困惑的缩进错误。无害 @OliverG 另外,顺便说一句,请始终提供minimal reproducible example。该代码的绝大部分可能已被删除以重现该错误,实际上,如果您尝试自己创建 minimal reproducible example,您可能会发现此错误。 【参考方案1】:

这是因为它没有为该类定义。 is_empty 是为内部类 _Item 定义的,而不是 PriorityQueueBase

编辑:我对您的代码进行了另一次尝试,我认为这只是一个缩进问题。如果您正确地取消缩进 is_empty 方法,应该可以解决问题。

【讨论】:

以上是关于为啥我的类不继承其基类中定义的方法?的主要内容,如果未能解决你的问题,请参考以下文章

从继承的类中覆盖虚拟方法但保留基类的注释[重复]

为啥我的类不继承父类?

派生类不从基类继承重载方法

基类不完整的继承

为啥java类不从实现的接口继承注解?

为啥我的性能慢到爬行我将方法移动到基类中?